在C:tee命令中管道产生空文件

时间:2014-05-10 03:41:25

标签: c exec pipe tee

我目前正致力于编程工作,以在C中实现以下内容:

(rev | sort | uniq -c | tee outfile2 | wc) <simple1.txt> outfile1

我已经看了很多关于这个特定任务的帖子,这个帖子似乎过去很受欢迎。有一个完全充实的解决方案,但根据我们教科书中提供的示例,我对我的方式更感兴趣。我已经成功地将数据传输到tee outfile2命令并在那里遇到了问题。但是,它似乎不是原子的?我以为数据流经管道应该等待执行直到读取?作为一个例子,我可以在运行时看到以下输出:

./pipeline -f simple1.txt aa aa aa ab ac ac ac ba ba bb ca cb cb cc cc cc db dc ev

18 18 54 All child processes reaped

我的代码成功创建了outfile2,但它是空的。第一组或第二组输出应该在文件中,因为输出到终端,因为我在tee的参数中包含了'-'。我认识到作业的后半部分还没有完成;我一步一步走。

我很感激这方面的帮助。我的代码如下:

/*
 * Filename: pipeline.c, read text from stdin to stdout via pipes
 * Author: Cody Crawford
 * Email: crawfoco@onid.orst.edu
 * Course: CS311-400
 * Homework: 5
 * Citations:
 *  - TLPI p 900-903
 *      - Help with pipes, child process, fork, general 'how to' for chaining multiple pipes...
 *  - My previous code, for getopt() usage
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <getopt.h> 

void errExit(char *mystring){
    printf("%s\n", mystring);
    exit(EXIT_FAILURE);
}

struct command_args{
    char out_filename[50];
}mystruct;

struct command_args grab_commands(int argc, char **argv, struct command_args mystruct){
    /*
     *  Grabs command-line arguments. I'm assuming only -f will be passed in with a filename.
     */
    char c = getopt(argc, argv, "f");
    int end_prog;

    if(c == 'f'){
        strcat( mystruct.out_filename, argv[2] );
    }else{
        printf("Error: Unrecognized Input '%c' '%s'\n", c, mystruct.out_filename);
        printf("Exiting.\n");
        exit(-1);
    }
    //printf("Received Op: %c && Output File: %s \n", c, mystruct.out_filename);
    return mystruct;
}

int main(int argc, char **argv){

    struct command_args mystruct;
    mystruct = grab_commands(argc, argv, mystruct);

    int pfd[2];                                     /* Pipe file descriptors */

    if (pipe(pfd) == -1)                            /* Create pipe */
        errExit("pipe");

    /***********************************************************************
     * First Child. 'rev' command
     ***********************************************************************/
    switch (fork()) {
    case -1:
        errExit("fork");

    case 0:             /* First child: exec 'ls' to write to pipe */
        if (close(pfd[0]) == -1)                    /* Read end is unused */
            errExit("close 1");

        /* Duplicate stdout on write end of pipe; close duplicated descriptor */

        if (pfd[1] != STDOUT_FILENO) {              /* Defensive check */
            if (dup2(pfd[1], STDOUT_FILENO) == -1)
                errExit("dup2 1");
            if (close(pfd[1]) == -1)
                errExit("close 2");
        }

        execlp("rev", "rev", mystruct.out_filename, (char *) NULL);          /* Writes to pipe */
        errExit("execlp rev 1");

    default:            /* Parent falls through to create next child */
        break;
    }
    /***********************************************************************
     * Second Child. 'sort' command
     ***********************************************************************/
    switch (fork()) {
    case -1:
        errExit("fork");

    case 0:             /* Second child: exec 'wc' to read from pipe */
        if (close(pfd[1]) == -1)                    /* Write end is unused */
            errExit("close 3");

        /* Duplicate stdin on read end of pipe; close duplicated descriptor */

        if (pfd[0] != STDIN_FILENO) {               /* Defensive check */
            if (dup2(pfd[0], STDIN_FILENO) == -1)
                errExit("dup2 2");
            if (close(pfd[0]) == -1)
                errExit("close 4");
        }

        execlp("sort", "sort", (char *) NULL);
        errExit("execlp sort 1");

    default: /* Parent falls through */
        break;
    }

    /***********************************************************************
     * Third Child. 'uniq -c' command
     ***********************************************************************/
    switch (fork()) {
    case -1:
        errExit("fork");

    case 0:             /* Second child: exec 'wc' to read from pipe */
        if (close(pfd[1]) == -1)                    /* Write end is unused */
            errExit("close 5");

        /* Duplicate stdin on read end of pipe; close duplicated descriptor */

        if (pfd[0] != STDIN_FILENO) {               /* Defensive check */
            if (dup2(pfd[0], STDIN_FILENO) == -1)
                errExit("dup2 3");
            if (close(pfd[0]) == -1)
                errExit("close 6");
        }
        sleep(1);
        execlp("uniq", "uniq", "-c", (char *) NULL);
        errExit("execlp uniq -c 1");

    default: /* Parent falls through */
        break;
    }
    /***********************************************************************
     * Fourth Child. 'tee outfile2' command
     ***********************************************************************/
    switch (fork()) {
    case -1:
        errExit("fork");

    case 0:             /* Second child: exec 'wc' to read from pipe */
        if (close(pfd[1]) == -1)                    /* Write end is unused */
            errExit("close 7");

        /* Duplicate stdin on read end of pipe; close duplicated descriptor */

        if (pfd[0] != STDIN_FILENO) {               /* Defensive check */
            if (dup2(pfd[0], STDIN_FILENO) == -1)
                errExit("dup2 4");
            if (close(pfd[0]) == -1)
                errExit("close 8");
        }
        sleep(5);
        execlp("tee", "tee", "outfile2", "-", (char *) NULL);
        errExit("execlp tee outfile2 1");

    default: /* Parent falls through */
        break;
    }
    /***********************************************************************
     * Fifth Child. 'wc' command
     ***********************************************************************/
    switch (fork()) {
    case -1:
        errExit("fork");

    case 0:             /* Second child: exec 'wc' to read from pipe */
        if (close(pfd[1]) == -1)                    /* Write end is unused */
            errExit("close 9");

        /* Duplicate stdin on read end of pipe; close duplicated descriptor */

        if (pfd[0] != STDIN_FILENO) {               /* Defensive check */
            if (dup2(pfd[0], STDIN_FILENO) == -1)
                errExit("dup2 5");
            if (close(pfd[0]) == -1)
                errExit("close 10");
        }

        execlp("wc", "wc", (char *) NULL);
        errExit("execlp wc 1");

    default: /* Parent falls through */
        break;
    }

    /* Parent closes unused file descriptors for pipe, and waits for children */

    if (close(pfd[0]) == -1)
        errExit("close 11");
    if (close(pfd[1]) == -1)
        errExit("close 12");
    while(wait() != -1);
    printf("All child processes reaped.\n");
    exit(EXIT_SUCCESS);

    return;
}

1 个答案:

答案 0 :(得分:2)

您只创建了一个管道,但命令行需要四个管道。这意味着第一个之后的命令正在争夺第一个的输出,基本上什么都没有效果。

您需要创建更多管道。你不必预先创建它们,但是你需要密切注意确保它们全部关闭。

此外,您正在实施与声称的管道略有不同的管道:

rev simple1.txt | sort | uniq -c | tee outfile2 | wc

你的程序似乎没有重定向wc的输出(这没关系; shell非常擅长为你做这个)。

还有另一个:你对getopt()的使用非常不正统。