显示的代码几乎可以工作(它削减了许多角落,但它有效),因为分叉的孩子确保执行进程将写入(在 的情况下ls
)和读取的文件描述符(在 的情况下wc
)是管道的适当端。您不必再做任何事情了;标准输入是文件描述符 0,因此wc
从标准输入读取没有(文件名)参数。 ls
始终写入标准输出,文件描述符 1,除非它正在写入错误消息。
代码片段中有三个进程;父进程和两个子进程,每个进程一个fork()
。父进程也应该关闭管道的两端;它只关闭一个。
通常,在对管道文件描述符执行dup()
或调用之后,应该关闭管道的两端。dup2()
您在这里侥幸逃脱,因为ls
生成数据并终止;你不会在所有情况下。
评论:
/* Set stdout to the input side of the pipe, and run 'ls'. */
不准确;您正在设置stdout
到管道的输出端,而不是输入端。
execv()
调用后您应该有一个错误退出;如果它们失败,它们会返回,并且该过程可能会造成严重破坏(例如,如果ls
失败,您最终会得到两个wc
运行的副本。
请注意在每个过程中仔细关闭管道的两端。一旦启动了两个子进程,父进程就不再使用管道。我将早期关闭的代码留filedes[1]
在原地(但将其从显式else
块中删除,因为以下代码也仅在执行时才else
执行)。我很可能closes()
在需要关闭文件的三个代码路径中的每一个中都保留了对。
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
int filedes[2];
int corpse;
int status;
pipe(filedes);
/* Run LS. */
pid_t pid = fork();
if (pid == 0)
{
/* Set stdout to the output side of the pipe, and run 'ls'. */
dup2(filedes[1], 1);
close(filedes[1]);
close(filedes[0]);
char *argv[] = {"ls", NULL};
execv("/bin/ls", argv);
fprintf(stderr, "Failed to execute /bin/ls\n");
exit(1);
}
/* Close the input side of the pipe, to prevent it staying open. */
close(filedes[1]);
/* Run WC. */
pid = fork();
if (pid == 0)
{
/* Set stdin to the input side of the pipe, and run 'wc'. */
dup2(filedes[0], 0);
close(filedes[0]);
char *argv[] = {"wc", NULL};
execv("/usr/bin/wc", argv);
fprintf(stderr, "Failed to execute /usr/bin/wc\n");
exit(1);
}
close(filedes[0]);
while ((corpse = waitpid(-1, &status, 0)) > 0)
printf("PID %d died 0x%.4X\n", corpse, status);
return(0);
}
示例输出:
$ ./pipes-14312939
32 32 389
PID 75954 died 0x0000
PID 75955 died 0x0000
$