带有fork和dup2的管道命令

问题描述 投票:0回答:3

我编写了以下代码,以便传递两个命令:

#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结果,但是然后等待输入。

我做错什么了吗?

编辑:我正在尝试重新实现外壳的行为

c redirect process pipe file-descriptor
3个回答
0
投票

问题是,当ls完成时,父进程将退出,这将关闭管道的读取端,这将导致错误传播到sort检测到的管道的写入端]并写入错误消息。

在shell中不会发生这种情况是因为shell处理管道的方式与简单示例程序不同,并且在您通过EOF之前,它一直保持管道的右侧打开并运行(可能在后台运行)( Ctrl-D转到sort程序。


0
投票

您的程序与外壳程序通常不完全相同。

您要用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);
}

0
投票

我终于找到了解决方案,我们已经接近:

#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仍处于打开状态

© www.soinside.com 2019 - 2024. All rights reserved.