使用 fork 和 dup2 管道命令
Pipe commands with fork and dup2
我写了下面的代码来传递两个命令:
#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 工作正常,除了这个。
当我通过管道将 sort 放入 ls 时,ls 会在标准输出上很好地打印其输出,但随后,sort 会抛出此错误:sort: Input/output error
.
当我在 bash 中键入 sort | ls
时,它会打印 ls 结果作为我的程序,然后等待输入。
我是不是做错了什么?
编辑:我正在尝试重新实现 shell 的行为
问题是当 ls
完成时,父进程将退出,这将关闭管道的读端,这将导致错误传播到管道的写端被 sort
检测到并写入错误消息。
它不会在 shell 中发生是因为 shells 处理管道的方式与您的简单示例程序不同,它使管道的右侧保持打开状态并且 运行 (可能在后台)直到你将 EOF
(Ctrl-D) 传递给 sort
程序。
您的程序并不完全等同于 shell 通常所做的。
您正在用 ls
替换父项;而 shell 将创建 who 子进程并连接它们并等待它们完成。
更像是:
#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);
}
我们需要在最后一个进程结束后关闭管道的读取端,这样,如果第一个进程尝试在管道上写入,则会抛出错误并退出进程,否则,如果仅从 stdin 读取为 sort
,它将继续读取,因为 stdin 仍处于打开状态
我写了下面的代码来传递两个命令:
#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 工作正常,除了这个。
当我通过管道将 sort 放入 ls 时,ls 会在标准输出上很好地打印其输出,但随后,sort 会抛出此错误:sort: Input/output error
.
当我在 bash 中键入 sort | ls
时,它会打印 ls 结果作为我的程序,然后等待输入。
我是不是做错了什么?
编辑:我正在尝试重新实现 shell 的行为
问题是当 ls
完成时,父进程将退出,这将关闭管道的读端,这将导致错误传播到管道的写端被 sort
检测到并写入错误消息。
它不会在 shell 中发生是因为 shells 处理管道的方式与您的简单示例程序不同,它使管道的右侧保持打开状态并且 运行 (可能在后台)直到你将 EOF
(Ctrl-D) 传递给 sort
程序。
您的程序并不完全等同于 shell 通常所做的。
您正在用 ls
替换父项;而 shell 将创建 who 子进程并连接它们并等待它们完成。
更像是:
#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);
}
我们需要在最后一个进程结束后关闭管道的读取端,这样,如果第一个进程尝试在管道上写入,则会抛出错误并退出进程,否则,如果仅从 stdin 读取为 sort
,它将继续读取,因为 stdin 仍处于打开状态