我正在尝试实现一个小型C程序,该程序将类似于Linux Shell命令提示符$ sort < Names.txt | uniq | wc - l
执行。为此,我正在使用execlp运行命令
结果程序将对名称的任意列表进行排序并删除重复的名称。它对列表进行排序是因为它需要相邻的重复行才能将其删除。然后只计算行数。
我已经发布了我的代码,目前我编译gcc -o sortuniqwc sortuniqwc.c
并运行./sortuniqwc < Names.txt
后才挂断它。如果我注释掉fd的管道,则每个系统调用似乎都能正常执行。我不确定为什么它不能正确地将进程传递给系统调用
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
int main(int argc, char *arv[])
{
pid_t pid;
int fd1[2]; //making file descriptor 1
if (pipe(fd1) == -1)
{
fprintf(stderr, "pipe failed");
return 1;
}
pid = fork(); //first child for sort
//printf("the pid for pipe parent is %d and the child pid is %d", getppid(), getpid());
if (pid < 0)
{
fprintf(stderr, "fork error");
return 1;
}
if (pid == 0)
{
dup2(fd1[1], 1);
close(fd1[0]);
//printf("the child process running sort is %d\n", getpid());
execlp("sort", "sort", NULL);
printf("sort exec - should not be here");
exit(0);
}
wait(0);
int fd2[2];
if (pipe(fd2) == -1)
{
fprintf(stderr, "pipe failed");
return 1;
}
pid = fork(); //second child for uniq
if (pid < 0)
{
fprintf(stderr, "fork error\n");
return 1;
}
if (pid == 0)
{
dup2(fd1[0], 0);
dup2(fd2[1], 1);
close(fd1[1]);
close(fd2[0]);
//printf("the child process running uniq is %d\n", pid);
execlp("/usr/bin/uniq", "uniq", NULL);
printf("uniq exec - you shouldnt be here");
exit(0);
}
wait(0);
pid = fork(); //3rd child process for wc
if (pid < 0)
{
fprintf(stderr, "fork failed\n");
return 1;
}
if (pid == 0)
{
dup2(fd2[0], 0);
close(fd2[1]);
close(fd1[0]);
close(fd1[1]);
//printf("the child process running wc is %d\n", getpid());
execlp("wc", "wc", "-l", NULL);
printf("wc exec - you shouldnt be here\n");
exit(0);
}
//parent
close(fd1[0]);
close(fd1[1]);
close(fd2[0]);
close(fd2[1]);
wait(NULL);
printf("CHILD COMPLETE \n");
}
答案 0 :(得分:1)
TL; DR-父级需要close()
附加到sort
的输出的管道写端副本。在第一次等待之前添加close(fd1[1])
可以“解决”该问题。
程序在对wait()
的第二次调用中“挂起”(等待uniq
子项退出 1 )。但是,uniq
永远不会退出,因为它的标准输入连接到fd1
管道的读取端,并且永远不会关闭。系统中此文件描述符有两个副本:第一个副本属于exec
的{{1}}的子进程,并且确实按sort
的预期关闭了。但是另一个副本属于不sort
的父进程。由于管道的写入端仍然至少有一个打开的文件描述符,因此管道不会关闭。
此解决方案还要求将 entire 排序输出缓冲在管道中(即内核中)。对于非平凡的输入,最好以相反的顺序分叉子节点,连接它们的所有管道,并让它们并行运行。这更接近于真实,强大的外壳程序。
1 或接收信号等,坚固的外壳应检查该信号。