使用进程运行带有管道

时间:2016-11-07 15:19:17

标签: c process pipe exec dup2

我对进程,管道和dup2还不熟悉,因此我希望有人帮我弄清楚我创建的程序有什么问题。该程序应该运行ls | wc。到目前为止,我得到的输出是:

wc : standard input : Bad file descriptor
        0         0         0
ls : write error : Bad file descriptor

收到此输出后,终端仍然接受输入。它就像wc仍在运行,虽然如果我先输入ls之类的命令(之前没有任何其他输入),它会运行它们并关闭它们。我尝试在之前/之后运行ps,当程序仍在运行时,它没有显示除了bash和ps之外的任何进程。 (我在Linux终端上运行这个程序)

这是我的代码:

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>
#include<string.h>
#include<sys/wait.h>
#include<errno.h>

int main(int argc, char* argv[]){
      pid_t pid;
      int fd[2];
      char com1[1024] = ("ls");
      char com2[1024] = ("wc");
      pipe(fd);
      pid = fork();
      if(pid == 0){
           open(fd[1]);
           dup2(fd[0],STDOUT_FILENO);
           close(fd[0]);
           execlp(com1, com1, NULL);
                  }
      else {
           pid = fork();
           if (pid == 0){
                   open(fd[0]);
                   dup2(fd[1],STDIN_FILENO);
                   close(fd[1]);
                   execlp(com2, com2, NULL);
                         }
           }
return 0;
}

请记住,我知道是否需要检查命令(例如if(pid<0)exit(0);),但我尽可能地简化了我的代码,以便查看是否由于疏忽而导致任何错误。 提前谢谢!

1 个答案:

答案 0 :(得分:1)

根据the pipe manual page

  

pipefd[0]指的是管道的读取端。 pipefd[1]指的是管道的写端。

现在从第一个子节点开始这一行,即调用ls命令的过程:

dup2(fd[0],STDOUT_FILENO);

在此,您将管道的读取端复制到STDOUT_FILENO,即写入输出的位置。如果你停下来思考一下,你会如何写入fd[0]之类的只读文件描述符?

与其他子进程相同,您可以在其中进行管道标准输入的 write 结束。

解决方案很简单:交换您复制的描述符的位置。第一个子进程使用fd[1],第二个子进程使用fd[0]

在您调用ls命令的第一个过程中:

dup2(fd[1],STDOUT_FILENO);
close(fd[1]);
execlp(com1, com1, NULL);

在第二个子进程中,您调用wc命令:

dup2(fd[0],STDIN_FILENO);
close(fd[0]);
execlp(com2, com2, NULL);