【问题标题】:Triple pipe in C using pipe(), execlp() and dup()C 中使用 pipe()、execlp() 和 dup() 的三重管道
【发布时间】:2014-11-24 04:38:06
【问题描述】:

考虑一个新的运算符“|||”。它将采用前一个程序的输出和 将其作为输入传递给三个不同的程序。给出一个程序triplepipe.c 执行以下命令: ls -l |独特的 ||| grep ^d, grep ^-, grep ^页。不要使用 popen() 库调用、system() 库调用或临时文件。

我正在使用以下逻辑来解决问题的第一部分。 'ls -l' 在 child1 中完成,在 child2 中使用 child1 的标准输出作为标准输入的 'uniq' 和在 parent 中使用 child2 的标准输出作为标准输入的 'grep ^d'。我可以看到输出。

但我不知道如何将 child2 的输出提供给满足限制集的三个单独的 grep。有人可以帮忙吗?

【问题讨论】:

  • 那 3 个 grep 命令的输出到哪里去了?在 bash 中,我会使用 tee 和进程替换来解决这个问题
  • 它们的输出到标准输出。

标签: c linux shell process pipe


【解决方案1】:

附上我的问题的答案。

void main() {
    int p1[2]; // pipe between ls | uniq and grep
    int p2[2]; // pipt between ls and uniq
    int p3[2]; // pipt between ls and uniq
    int p4[2]; // pipt between ls and uniq
    int p5[2]; // pipt between ls and uniq
    char buff[200];
    char data[10 * 1024];
    int count;
    int teelen;
    pid_t ret;
    pid_t chd;

    pipe (p1);
    ret = fork();
    if (ret == 0) {
        pipe (p2);
        chd = fork();
        if (chd == 0) {
            close (1); // close stdout
            dup (p2[1]); // dup stdout to p2's out
            close (p2[0]); // close p2's in
            execlp ("ls", "ls", "-l", NULL); // execute command
            exit (0);
        }
        if (chd > 0) {
            close (0); // close stdin
            dup (p2[0]); // dup stdin to p2's in
            close (p2[1]); // close p2's out
            wait(NULL); // wait for child to finish
            close (1); // close stdout
            dup (p1[1]); // dup stdout to p1's out
            close (p1[0]); // close p1's in 
            execlp ("uniq", "uniq", NULL); // command
            exit (0);
        }
    }
    if (ret > 0) {
        close (0); // close stdin
        dup (p1[0]); // dup stdin to p1's in
        close(p1[1]);
        wait(NULL); // wait for child to complete
        memset (data, '\0', sizeof(data));
        do {
            memset(buff, '\0', sizeof(buff));
            count = read(p1[0], buff, 199);
            buff[count] = '\0';
            if (count == 0)
                break;
            strcat (data, buff);
        } while(1);
        pipe (p3);
        close(p1[0]);
        write (p3[1], data, sizeof (data));
        fsync(p3[1]);
        if (fork() == 0) {
            int c;
            close(0);
            dup(p3[0]);
            close(p3[1]);
            execlp ("grep", "grep", "-a", "^d", NULL);
            exit (0);
        }
        close(p3[1]);
        wait(NULL);
        pipe (p4);
        write (p4[1], data, sizeof (data));
        if (fork() == 0) {
            close(0);
            dup(p4[0]);
            close(p4[1]);
            execlp ("grep", "grep", "-a", "^-", NULL);
            exit (0);
        }
        close(p4[1]);
        wait(NULL);
        pipe (p5);
        write (p5[1], data, sizeof (data));
        if (fork() == 0) {
            close(0);
            dup(p5[0]);
            close(p5[1]);
            execlp ("grep", "grep", "-a", "^c", NULL);
            exit (0);
        }
        close(p5[1]);
        wait(NULL);
    }
    }

【讨论】:

  • 在这样的管道中,您希望所有子进程同时执行。你不应该在你的任何 fork() 调用之前调用 wait() 。有了你所拥有的,你最终会阻塞大文件,因为管道缓冲区将填满,因为此时没有任何数据消耗数据。
  • 感谢您注意到这一点。但问题要求结果是连续的。因此等待。
  • 如果是这种情况,你就完蛋了,除非你能保证数据足够小,以至于你可以将它们全部缓冲在内存中。无论如何,您仍然只需要最后三个孩子之间的等待。 ls -l 和 uniq 需要同时运行。
  • 我会用一个巨大的输出列表来检查它。感谢您的评论:)
【解决方案2】:

引用“管道只是文件”

认为您已上当,目前您的数据在其中一个孩子的管道中。现在只需从管道中读取并使用 Write System 调用并写入 3 个不同的管道。

从那里您可以在 3 个不同的过程中以不同的方式处理数据

认为这就是你所需要的;)

【讨论】:

    【解决方案3】:

    这个任务的一部分基本上是实现一个3路tee。设置管道和子进程后,您必须进入一个读取一次并写入 3 次的循环,直到读取到达 EOF。

    在 Linux 中还有一个 tee 系统调用,它不在您的禁止列表中。它非常适合这个程序,但它相当新,所以你的老师很可能还不知道它。

    【讨论】:

    • 非常感谢您的指点。我会调查并报告。
    • 我尝试使用 tee()。由于输入来自 stdout 并且 tee() 需要将字符串的长度作为参数传递,我不知道如何实现这一点。
    猜你喜欢
    • 2013-05-06
    • 1970-01-01
    • 2017-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-31
    相关资源
    最近更新 更多