使用一系列管道过滤文本文件

时间:2015-02-12 18:52:59

标签: c linux

我正在完成一项家庭作业,我们应该通过一系列管道过滤输入。我已经让程序在cat管道文件到第一个过滤器而没有问题,但是当我尝试添加第3个分支时,我遇到程序刚挂起并需要中断退出的问题

#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    int pfd[2];
    if(pipe(pfd) == -1) {
        perror("could not create pipes");
        exit(EXIT_FAILURE);
    }

    switch( fork() ) {
        case -1:
            perror("fork 1");
            exit(EXIT_FAILURE);
        case 0:
            /* child:
             *  r = false
             *  w = true
             */
            if( close(pfd[0]) == -1 ) {
                perror("close 1");
                exit(EXIT_FAILURE);
            }

            if( pfd[1] != STDOUT_FILENO ) {
                if( dup2(pfd[1], STDOUT_FILENO) == -1 ) {
                    perror("dup2 1");
                    exit(EXIT_FAILURE);
                }
                if( close(pfd[1]) == -1 ) {
                    perror("close 2");
                    exit(EXIT_FAILURE);
                }
            }

            execlp("cat", "cat", argv[1], (char *) NULL);
            perror("cat failed");
            exit(EXIT_FAILURE);
        default:
            /* parent */
            break;
    }

    switch( fork() ) {
        case -1:
            perror("fork 2");
            exit(EXIT_FAILURE);
        case 0:
            /* child:
             *  r = true
             *  w = true
             */
            if( pfd[0] != STDIN_FILENO ) {
                if( dup2(pfd[0], STDIN_FILENO) == -1 ) {
                    perror("dup2 2");
                    exit(EXIT_FAILURE);
                }
                if( close(pfd[0]) == -1 ) {
                    perror("close 4");
                    exit(EXIT_FAILURE);
                }
            }
            if( pfd[1] != STDOUT_FILENO ) {
                if( dup2(pfd[1], STDOUT_FILENO) == -1 ) {
                    perror("dup2 3");
                    exit(EXIT_FAILURE);
                }
                if( close(pfd[1]) == -1 ) {
                    perror("close 5");
                    exit(EXIT_FAILURE);
                }
            }

            execlp("sed", "sed", "s/[^a-zA-Z]/ /g", (char *) NULL);
            perror("sed failed");
            exit(EXIT_FAILURE);
        default:
            /* parent */
            break;
    }

    switch( fork() ) {
        case -1:
            perror("fork 3");
            exit(EXIT_FAILURE);
        case 0:
            /* child:
             *  r = true
             *  w = false
             */
            if( close(pfd[1]) == -1 ) {
                perror("close 5");
                exit(EXIT_FAILURE);
            }

            if( pfd[0] != STDIN_FILENO ) {
                if( dup2(pfd[0], STDIN_FILENO) == -1 ) {
                    perror("dup2 4");
                    exit(EXIT_FAILURE);
                }
                if( close(pfd[0]) == -1 ) {
                    perror("close 6");
                    exit(EXIT_FAILURE);
                }
            }

            execlp("tr", "tr", "[A-Z]", "[a-z]", (char *) NULL);
            perror("tr failed");
            exit(EXIT_FAILURE);
        default:
            /* parent */
            break;
    }

    if( close(pfd[0]) == -1 ) {
        perror("close 7");
        exit(EXIT_FAILURE);
    }
    if( close(pfd[1]) == -1 ) {
        perror("close 8");
        exit(EXIT_FAILURE);
    }

    if( wait(NULL) == -1 ) {
        perror("wait 1");
        exit(EXIT_FAILURE);
    }
    if( wait(NULL) == -1 ) {
        perror("wait 2");
        exit(EXIT_FAILURE);
    }

    if( wait(NULL) == -1 ) {
        perror("wait 3");
        exit(EXIT_FAILURE);
    }

    exit(EXIT_SUCCESS);
}

我已经根据Michael Kerrisk的 Linux编程接口中的示例来创建此代码(第44.4节)。

1 个答案:

答案 0 :(得分:1)

您写道,您需要&#34;通过一系列管道过滤输入&#34;。但是我看到你只创建了一个管道(一个管道()调用创建一个管道并返回两个文件描述符 - 两个管道末端)。如果您有3个孩子 - 您需要至少2个管道以正确的顺序连接。

stdin -> child1 -> PIPE1 -> child2 -> PIPE2 -> child3 -> stdout

Q&A应该会有所帮助。