我正在尝试在 C 中实现管道$ ls | wc | wc
。
我写了以下代码 -
#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
void run_cmd(char *cmd, int* fd_in, int* fd_out)
{
int c = fork();
if (c==0)
{
if (fd_in != NULL)
{
close(fd_in[1]);
dup2(fd_in[0], 0);
}
if (fd_out != NULL)
{
close(fd_out[0]);
dup2(fd_out[1],1);
}
execlp(cmd, cmd, NULL);
}
}
int main(int argc, char **argv)
{
int fd_1[2], fd_2[2], i;
pipe(fd_1);
pipe(fd_2);
run_cmd(argv[1], NULL, fd_1);
for( i=2; i<argc-1; i++)
{
if (i%2 == 0)
run_cmd(argv[i], fd_1, fd_2);
else
run_cmd(argv[i], fd_2, fd_1);
}
if (i%2 == 0)
run_cmd(argv[i], fd_1, NULL);
else
run_cmd(argv[i], fd_2, NULL);
}
这适用于两个参数,例如 - $./a.out ls wc
但是当我尝试使用两个以上的参数时,它不起作用。
有人可以告诉我我的代码出了什么问题,或者任何其他方法可以做到这一点吗?
这几乎没有错误检查,但为什么这么复杂?
int main (int argc, char ** argv) {
int i;
for( i=1; i<argc-1; i++)
{
int pd[2];
pipe(pd);
if (!fork()) {
dup2(pd[1], 1); // remap output back to parent
execlp(argv[i], argv[i], NULL);
perror("exec");
abort();
}
// remap output from previous child to input
dup2(pd[0], 0);
close(pd[1]);
}
execlp(argv[i], argv[i], NULL);
perror("exec");
abort();
}
如果你仍然对为什么你的来源不起作用感兴趣(无论如何,谢尔盖的解决方案更好):
问题在于没有关闭父进程中fd_1
的写入端。因此,argv[1]
和父母都是该管道的作者,这引起了混乱。请不要询问更多详细信息(尤其是为什么只使用一个管道时不会发生概率),但是如果您在第一次调用run_cmd()
后添加close( fd_1[1] );
,您的原始源将与树进程一起运行