我编写了以下代码,以便传递两个命令:
#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都可以正常工作,除了这一对。当我通过管道将ls排序时,ls会在stdout上很好地打印其输出,但是随后,排序会抛出此错误:sort: Input/output error
。
当我在bash中键入sort | ls
时,它将在我的程序中输出ls结果,但是然后等待输入。
我做错什么了吗?
编辑:我正在尝试重新实现外壳的行为
问题是,当ls
完成时,父进程将退出,这将关闭管道的读取端,这将导致错误传播到sort
检测到的管道的写入端]并写入错误消息。
在shell中不会发生这种情况是因为shell处理管道的方式与简单示例程序不同,并且在您通过EOF
之前,它一直保持管道的右侧打开并运行(可能在后台运行)( Ctrl-D转到sort
程序。
您的程序与外壳程序通常不完全相同。
您要用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);
}
我们需要在最后一个进程结束后关闭管道的读取端,这样,如果第一个进程尝试在管道上进行写操作,将抛出错误并且该进程将退出,否则,如果仅从stdin中读取作为sort
,它将继续读取,因为stdin仍处于打开状态