【问题标题】:How to loop through stdin & pipe output to a child execl command in C?如何通过标准输入和管道输出循环到 C 中的子 execl 命令?
【发布时间】:2013-05-11 22:20:36
【问题描述】:

我一直在试图弄清楚如何从文件中循环遍历标准输入,然后将其发送给使用 execl() 对 int 进行排序的子进程。下面的代码的工作原理是它获取文件并对行进行排序,但我没有看到我添加的“句子结尾”调试字符串。不知何故,这部分代码被绕过了。我可以使用一些帮助来理解从文件中传入的数据流,然后打印到屏幕上。

int main(int argc, char *argv[])
{
  pid_t p;
  int status;
  int fds[2];
  FILE *writeToChild;
  char word[50];

  if(pipe(fds) == -1) {
    perror("Error creating pipes");
    exit(EXIT_FAILURE);
  }

  switch(p = fork()) {
  case 0: //this is the child process
    close(fds[1]); //close the write end of the pipe
    execl("/usr/bin/sort", "sort", (char *) 0);
    break;
  case -1: //failure to fork case
    perror("Could not create child");
    exit(EXIT_FAILURE);
  default: //this is the parent process
    close(fds[0]); //close the read end of the pipe
    writeToChild = fdopen(fds[1], "w");
    wait(&status);
    break;
  }

  while (fscanf(stdin, "%s", word) != EOF) {
    //the below isn't being printed.  Why?
    fprintf(writeToChild, "%s end of sentence\n", word); 
  }

  return 0;
}

【问题讨论】:

    标签: c unix fork pipe stdin


    【解决方案1】:

    您的主要问题是您将wait() 放在错误的位置。在你给它写任何东西之前,你等待孩子死去。您还有一个次要问题,即不将管道的读取端重定向到sort 进程的标准输入。

    你没有在孩子中关闭fds[0];清洁建议你应该。您确实需要在等待之前fclose(writeToChild);在父级关闭子级管道之前,排序不会停止。

    这些变化(以及其他一些变化)导致:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main(void)
    {
        pid_t p;
        int status;
        int fds[2];
        FILE *writeToChild;
        char word[50];
    
        if (pipe(fds) == -1)
        {
            perror("Error creating pipes");
            exit(EXIT_FAILURE);
        }
    
        switch (p = fork())
        {
            case 0: //this is the child process
                close(fds[1]); //close the write end of the pipe
                dup2(fds[0], 0);
                close(fds[0]);
                execl("/usr/bin/sort", "sort", (char *) 0);
                fprintf(stderr, "Failed to exec sort\n");
                exit(EXIT_FAILURE);
    
            case -1: //failure to fork case
                perror("Could not create child");
                exit(EXIT_FAILURE);
    
            default: //this is the parent process
                close(fds[0]); //close the read end of the pipe
                writeToChild = fdopen(fds[1], "w");
                break;
        }
    
        if (writeToChild != 0)
        {
            while (fscanf(stdin, "%49s", word) != EOF)
            {
                //the below isn't being printed.  Why?
                fprintf(writeToChild, "%s end of sentence\n", word); 
            }
            fclose(writeToChild);
        }
    
        wait(&status);
    
        return 0;
    }
    

    【讨论】:

    • 这是一个巨大的帮助。谢谢你。我有几个跟进问题。 dup2(fds[0], 0); 行复制了 fds 管道的读取端?看起来您在使用close(fds[0]); 之后立即关闭了管道的读取端?如果是这样,为什么在调用excel排序之前关闭它?
    • dup2() 确保排序的标准输入是管道,但您只需要打开两个文件描述符(0 和 fds[0])之一,因此关闭第二个描述符。当您将管道复制到标准输入或标准输出时,这是正常的;如果使用dup2() 将该管道连接到标准输入或标准输出,则关闭pipe() 返回的管道的两端。由于父进程写入管道(不使用dup2()),它不会关闭它正在写入的管道的末端,直到它完成。您可以在父级中使用dup2(fds[1], 1) 并关闭fds[1]
    猜你喜欢
    • 1970-01-01
    • 2021-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-25
    • 1970-01-01
    • 2020-11-02
    • 1970-01-01
    相关资源
    最近更新 更多