[英]Pipe commands with fork and dup2
我为 pipe 两个命令编写了以下代码:
#include <stdlib.h>
#include <unistd.h>
char *program_1[3] = {"/bin/cat", "/dev/random", NULL};
char *program_2[2] = {"/bin/ls", NULL};
char *program_3[2] = {"/usr/bin/sort", NULL};
int main(void)
{
int fd[2];
int pid;
pipe(fd);
if ((pid = fork()) == 0) //Child process
{
dup2(fd[1], STDOUT_FILENO);
close(fd[0]);
execve(program_3[0], program_3, NULL);
}
else if (pid > 0) //Parent process
{
dup2(fd[0], STDIN_FILENO);
close(fd[1]);
execve(program_2[0], program_2, NULL);
}
return (EXIT_SUCCESS);
}
每对 program_x / program_y 其中 x,= y 工作正常。 除了这个,当我将 pipe 排序为 ls 时,ls 会在标准输出上很好地打印其 output,但随后:排序抛出此错误: sort: Input/output error
。
当我输入sort | ls
sort | ls
进入 bash,它将 ls 结果打印为我的程序,然后等待输入。
我做错了吗?
编辑:我正在尝试重新实现 shell 的行为
问题是当ls
完成时,父进程将退出,这将关闭 pipe 的读端,这将导致错误传播到 pipe 的写端,通过sort
检测并写入错误信息。
在 shell 中不会发生这种情况是因为 shell 处理管道的方式与您的简单示例程序不同,并且它使 pipe 的右侧保持打开并运行(可能在后台),直到您通过EOF
( Ctrl-D )到sort
程序。
您的程序并不完全等同于 shell 通常所做的。
您正在用ls
替换父级; 而 shell 将创建谁子进程并连接它们并等待它们完成。
它更像是:
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
char *program_2[2] = {"/bin/ls", NULL};
char *program_3[2] = {"/usr/bin/sort", NULL};
int main(void)
{
int fd[2];
pid_t pid;
pid_t pid2;
pipe(fd);
if ((pid = fork()) == 0) //Child process
{
dup2(fd[1], STDOUT_FILENO);
close(fd[0]);
execve(program_3[0], program_3, NULL);
}
else if (pid > 0) //Parent process
{
if ( (pid2 = fork()) == 0) {
dup2(fd[0], STDIN_FILENO);
close(fd[1]);
execve(program_2[0], program_2, NULL);
}
}
waitpid(pid, 0, 0);
waitpid(pid2, 0, 0);
return (EXIT_SUCCESS);
}
我终于找到了解决方案,我们接近:
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
char *cat[3] = {"/bin/cat", "/dev/random", NULL};
char *ls[2] = {"/bin/ls", NULL};
char *sort[2] = {"/usr/bin/sort", NULL};
int main(void)
{
int fd[2];
pid_t pid;
pid_t pid2;
pipe(fd);
if ((pid = fork()) == 0)
{
dup2(fd[1], STDOUT_FILENO);
close(fd[0]);
execve(cat[0], cat, NULL);
}
else if (pid > 0)
{
if ( (pid2 = fork()) == 0)
{
dup2(fd[0], STDIN_FILENO);
close(fd[1]);
execve(ls[0], ls, NULL);
}
waitpid(pid2, 0, 0);
close(fd[0]);
}
waitpid(pid, 0, 0);
return (EXIT_SUCCESS);
}
一旦最后一个进程结束,我们需要关闭 pipe 的读取端,这样,如果第一个进程尝试在 pipe 上写入,则会抛出错误并退出进程,否则如果它只从标准输入读取sort
,它将继续阅读,因为标准输入仍处于打开状态
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.