如何在Unix C中使用两个管道?

时间:2010-10-30 17:04:20

标签: c unix

我有一项功课要做如下:

在C中编写一个程序,创建一个也会创建子项的子项,在三个进程之间建立管道,第一个进程(父)将连接第二个(子),子进程将与第三个进程连接(子进程)的孩子)。我们的程序应该显示使用bash作为默认shell的系统用户总数。该程序的结果应与“cat / etc / passwd | grep”/ bin / bash $“| wc-l”

相同

我对第一个孩子以及我们关闭第一个管道并同时打开第二个管道的方法感到困惑。如果你用正确的代码回复我,我将立即解决它。

谢谢。

这是我到目前为止所写的内容:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
main()
{
int pid, pid2;
int fd[2];
int fd2[2];
char *arg[3];
char *arg2[3];
char *arg3[3];  
if (pipe(fd) == -1)
{
    perror("pipe");
    exit(1);
}
pid = fork();
if (pid == -1)
{
    perror("fork");
    exit(2);
}
if (pid == 0)
{
    if (pipe(fd2) == -1)
    {
        perror("pipe");
        exit(11);
    }
    pid2=fork();
    if(pid2 == -1)
    {
        perror("fork 2");
        exit(22);
    }
    if (pid2 == 0)
    {
        //i am child 2 (child of the child)
        close (fd2[1]);
        dup2 (fd2[0],0);
        close (fd2[0]);
        arg3[0] = "wc";
        arg3[1] = "-l";
        arg3[2] = NULL;
        execvp("wc", arg3);
        perror("execvp second child");
    }
    else
    {
        //i am child 1
        close (fd[1]);
        dup2(fd[0],0);
        close (fd[0]);
        close (fd2[0]);
        dup2(fd2[1],1);
        close (fd2[1]);
        arg2[0] = "grep";
        arg2[1] = "/bin/bash$";
        arg2[2] = NULL;
        execvp("grep", arg2);
        perror("execvp first child");
    }
}
else
{
    //i 'm the father
    close (fd[0]);
    dup2(fd[1],1);
    close (fd[1]);
    arg[0] = "cat";
    arg[1] = "/etc/passwd";
    arg[2] = NULL;
    execvp("cat", arg);
    perror("execvp father");    
}   

}

1 个答案:

答案 0 :(得分:3)

您的计划非常有效。缺少的是

    //i am child 2 (child of the child)
    close (fd[1]);
    close (fd[0]);

你调用fd的管道用于'cat'和'grep'之间的通信。当前代码中发生的事情是cat转储文件并退出,关闭其输出。 Grep读取所有内容并等待其输入的EOF。由于“child 2”仍然打开管道的输入端(它通过fork继承它),grep会永远等待。如果运行你的程序,然后输入ps,你应该看到一个grep和一个wc等待完成。

在构造像这样的管道时,你通常会做的另一件事是安排它,以便最后的任务(在这种情况下是wc)是shell正在等待的那个。如上所述,当您的程序从shell运行时,它将在cat完成时显示完成,并且wc的输出将打印为就像来自后台任务一样。如果您安排管道以便wc位于“我是孩子1”下,那么shell将等待wc。

或者你可以关闭三个进程的所有,并且“child 1”会在退出之前调用wait()等待所有进程。等待过程就像你自己的小壳一样。