使用进程通过管道运行命令
问题描述:
我还不熟悉进程,管道和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);
),但我想简化我的代码尽可能多地查看是否由于粗心导致任何错误。 提前谢谢!
答
pipefd[0]
指管的读端。pipefd[1]
指的是管道的写入结束。
现在从第一个孩子这一行,调用ls
命令的过程:
dup2(fd[0],STDOUT_FILENO);
在这里,您复制阅读管结束STDOUT_FILENO
,即,其中输出写入。如果你停下来思考一下,你会如何写入一个只读的文件描述符如fd[0]
?
与其他子进程相同,你在这里编写写入管道标准输入结束。
解决方法很简单:交换重复描述符的位置。第一个子进程使用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);
这是否代码甚至编译?它至少应该使编译器对你发出警告。调用'open(fd [0])'(当然'open(fd [1])')是无效的,应该删除。 –
至于你的问题,我建议你阅读[管'手册页](http://man7.org/linux/man-pages/man2/pipe.2.html)。请密切注意哪些描述符是管道的读取和写入结束。 –
此代码编译没有任何错误到目前为止,我删除了open()命令,并得到相同的输出 –