这本质上是shell在构建重定向链时所做的事情,即类似
ls | grep foo | sort | uniq
有一些关于 Unix 编程的优秀介绍性文本,其中通过本书实现了一个简单的 shell。 shell 的任务之一是重定向。其中一本书是 Michael K. Johnson 和 Erik W. Troan 的《Linux 应用程序编程》。
本书首页:http://ladweb.net/
要为 N 个进程构建一个重定向链,您需要 N-1 个管道。对于每个重定向,您使用pipe(int fds[2]) 系统调用创建一个管道。在fork()ing 之后,但在execving 之前使用dup2(int from, int to) 将管道的末端“连接”到每个进程的标准输入(0)或标准输出。这是一个过于简化的代码,没有错误检查:
int pipe_A[2];
int pipe_B[2];
pipe(pipe_A);
pipe(pipe_B);
pid_t pid_A, pid_B, pid_C;
if( !(pid_A = fork()) ) {
dup2(pipe_A[1], 1); /* redirect standard output to pipe_A write end */
execv(...);
}
if( !(pid_B = fork()) ) {
dup2(pipe_A[0], 0); /* redirect standard input to pipe_A read end */
dup2(pipe_B[1], 1); /* redirect standard output to pipe_B write end */
execv(...);
}
if( !(pid_C = fork()) ) {
dup2(pipe_B[0], 0); /* redirect standard input to pipe_B read end */
execv(...);
}
请注意,管道的数组索引的选择方式可以反映标准输入/输出文件描述符(如果它们用于 stdio 重定向)。这种选择不是任意的。
当然,您可以将管道连接到任何文件描述符(例如,有些应用程序希望它们的父级打开,例如 fd 3 和 4,连接到管道)并且大多数 shell 也直接支持这一点(例如 1> &3 将标准输出重定向到 fd 3)。但是,pipe(int fds[2]) 的数组索引当然是 0 和 1。我只是这么说,因为我有一些狂热的编程学生,他们盲目地将目标 fds 也用于管道系统调用数组。
等待所有子进程完成使用waitpid(-1, NULL, 0) - 我认为这是我的预回答者的意思 -1,这意味着:等待所有子进程完成。另一个选项是在循环中调用wait(),这将返回刚刚终止的孩子的pid。如果再次调用并且仍然有一个孩子在运行,它将再次阻塞。如果没有孩子,则返回-1;我更喜欢waitpid 解决方案。