【问题标题】:Using processes to run commands with pipes使用进程通过管道运行命令
【发布时间】:2016-11-07 15:19:16
【问题描述】:

我对流程、管道和 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&lt;0)exit(0);),但我尝试尽可能简化我的代码,以查看是否由于粗心而出现任何错误。 提前谢谢!

【问题讨论】:

  • 那段代码还能编译吗?它至少应该导致编译器向你发出警告。调用open(fd[0])(当然还有open(fd[1]))无效,应该删除。
  • 至于你的问题,我建议你阅读the pipe manual page。密切注意哪些描述符是管道的读端和写端。
  • 到目前为止,这段代码编译没有任何错误,我删除了 open() 命令并且得到了相同的输出
  • 你也解决了其他问题吗?使用错误的管道末端?
  • 我还处于死胡同。无法弄清楚如何正确使用 execlp。我想我了解管道背后的理论,但我仍然无法使用它们。

标签: c process pipe exec dup2


【解决方案1】:

根据the pipe manual page

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

现在从第一个子进程中取出这一行,即调用ls 命令的进程:

dup2(fd[0],STDOUT_FILENO);

在这里,您将管道的 read 端复制到 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);

【讨论】:

    最近更新 更多