我对进程,管道和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);
),但我尽可能地简化了我的代码,以便查看是否由于疏忽而导致任何错误。
提前谢谢!
答案 0 :(得分:1)
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);