如何从在 C 中存储 shell 脚本输出的指针获取多个字符串?

Posted

技术标签:

【中文标题】如何从在 C 中存储 shell 脚本输出的指针获取多个字符串?【英文标题】:How to get multiple strings from pointer that stores the output of a shell script in C? 【发布时间】:2020-05-24 18:20:05 【问题描述】:

我正在尝试使用命名管道 (fifo) 用 C 语言编写代码,客户端在其中询问有关目录的信息。

服务器检查目录是否存在,并返回目录的大小、文件和子目录的数量。 该请求还可以指定获取文件和子目录的名称。

客户端获取目录的名称作为参数,也是-d 选项的规范。 服务器执行一个shell脚本来解决这个问题。

我已经问过一个关于这个主题的问题,并且对代码进行了一些改进,但仍然无法使其正常运行。

这里是问题的链接:How to pass multiple arguments to client (fifo)?

我现在的问题是服务器只打印出一个文件名,而不是作为参数提供给客户端的目录中的所有文件名和子目录。

这是修改后的服务器代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "header.h"

int f;
Message msg;

int main() 
    if (mkfifo(FIFONAME, S_IFIFO | 0666) < 0)  /*Creating server fifo*/
        perror("Failed creating own fifo");
        printf("Server: Failed creating fifo_%d file\n", getpid());
        unlink(FIFONAME);
        exit(1);
    

    if ((f = open(FIFONAME, O_RDONLY)) < 0) 
        perror("Failed opening fifo");
        unlink(FIFONAME);
        exit(1);
           

    printf("Server is working\n");
    while (1)  /*Infinite loop, waiting for client requests*/
        if ((read(f, &msg, sizeof(msg)))) 
            if (strcmp(msg.dir, "exit") == 0) 
                close(f);
                unlink(FIFONAME);
                exit(1);
            

            switch (fork()) 
              case -1: 
                perror("Fork error\n");
                exit(1);
              

              case 0: 
                char command[MAXLEN];
                sprintf(command,"./shell.sh %s %s", msg.dir, msg.spec);
                FILE *g;
                if ((g = popen(command, "r")) == NULL) 
                    perror("Popen error");
                    exit(1);
                

                fgets(msg.dir, MAXLEN, g);
                fgets(msg.spec, MAXLEN, g);
                char result[MAXLEN];
                sprintf(result, "fifo_%d", msg.pid);
                msg.pid = getpid();
                int op;
                op = open(result, O_WRONLY);
                write(op, &msg, sizeof(msg));
                close(op);
                exit(0);
              
            
        
    
    return 0;

以及客户端代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "header.h"

int f, fc;
Message msg;
char fifoname[MAXLEN];

int main(int argc, char *argv[]) 
    if (argc == 1) 
        printf("Usage: %s directory name\n",argv[0]);
        exit(1);
    
    sprintf(fifoname, "fifo_%d", getpid());
    if (strcmp(argv[1], "0"))
        if (mkfifo(fifoname, S_IFIFO | 0666) < 0)  /*Creating own FIFO file for result*/
            perror("Failed creating own clientfifo");
            printf("Client error: Failed creating fifo_%d file\n", getpid());
            exit(2);
        

    if ((f = open(FIFONAME, O_WRONLY)) < 0)  /*Opening serverfifo for writing*/
        perror("Failed connecting to server");
        exit(3);
    

    strcpy(msg.dir, argv[1]);
    strcpy(msg.spec, argv[2]); 
    msg.pid = getpid();
    write(f, &msg, sizeof(msg));

    if (strcmp(argv[1], "exit"))  /* The client is not expecting any result 
                                      because the server stopped*/
        if ((fc = open(fifoname, O_RDONLY)) < 0)  /*Opening own fifo for reading*/
            perror("Failed opening own fifo");
            printf("Client error: Failed opening own %s file\n", fifoname);
            exit(4);        
        
        read(fc, &msg, sizeof(msg));
        printf("Client %d, received: %s%s\n", getpid(), msg.dir, msg.spec);
        close(fc);
    

    unlink(fifoname);
    close(f);
    exit(0);

通用头文件:

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>

#define FIFONAME "server_fifo"
#define MAXLEN 1000

typedef struct 
    int pid; /*folyamat azonositoja*/
    char dir[MAXLEN];
    char spec[MAXLEN];
 Message;

我得到的输出是:

-bash-4.1$ ./client dir -d
Client 42723, received: 16K,2 directories, 2 files
a

虽然它应该是这样的:

-bash-4.1$ ./client dir -d
Client 42723, received: 16K,2 directories, 2 files
a
b
dir1
dir2

为了获得完整的输出需要修改什么?

【问题讨论】:

【参考方案1】:

问题出在 server.c 中的第 52 行。 您正在使用fgets() 将输出复制到msg.spec。 但是fgets() 停止在换行符('\n')处接受输入。 因此,您只会看到一个结果。

要克服这个问题,您可以执行以下操作:

char str[100]; // arbitrary length
while(fgets(str, MAXLEN, g))

     strcat(msg.spec, str);

这会在每次迭代中不断获取输入,并将每一行连接到前一个输出。

【讨论】:

谢谢。同时我想通了:D

以上是关于如何从在 C 中存储 shell 脚本输出的指针获取多个字符串?的主要内容,如果未能解决你的问题,请参考以下文章

C-学会使用指针

linux下如何用c语言调用shell命令

如何将命令存储在 shell 脚本的变量中?

用于打开 URL 的 Shell 脚本

如何使用sqlplus在shell中存储存储过程返回的多个输出列

如何将一shell脚本中的每一步命令执行结果输出到指定日志文件中