dat*_*olf 19
这基本上是shell在构建重定向链时所做的事情,例如
ls | grep foo | sort | uniq
Run Code Online (Sandbox Code Playgroud)
关于Unix编程有一些优秀的介绍性文本,其中通过本书实现了一个简单的shell.shell的任务之一是重定向.其中一本书是Michael K. Johnson和Erik W. Troan的"Linux应用程序编程".
该书的主页:http://ladweb.net/
要为N个进程构建重定向链,您需要N-1个管道.对于每个重定向,您使用pipe(int fds[2])
系统调用创建管道.之后fork()
,但在execv
使用之前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(...);
}
Run Code Online (Sandbox Code Playgroud)
请注意,管道的数组索引已被选择,如果它们用于stdio重定向,则它们反映标准输入/输出文件描述符.这种选择并非随意.
当然你可以将管道连接到任何文件描述符(例如,有一些应用程序,希望它们的父项打开,比如fd 3和4,连接到管道),大多数shell也直接支持这个(例如1>&3将重定向) stdout进入fd 3).但是,数组索引pipe(int fds[2])
当然是0和1.我只是告诉这个,因为我有一些货物狂热编程的学生,他们盲目地将目标fds也用于管道系统调用阵列.
等待所有孩子完成使用waitpid(-1, NULL, 0)
- 我认为这是我的前回答者的意思-1,这意味着:等待所有子进程完成.另一种选择是调用wait()
一个循环,它将返回刚刚终止的子进程的pid.如果再次调用并且仍然有一个孩子在运行,它将再次阻止.如果没有孩子,它将返回-1; 我更喜欢waitpid
解决方案.
是的,这相当简单,您只需要在父级中创建所有管道,并记住关闭子级中不需要的管道/管道末端。
让不使用管道的 FD 处于打开状态是一种失败,因为这可能会让其他人永远等待管道的末端。所有写入器必须在读取器收到 EOF 之前关闭。