简体   繁体   中英

How to run a command in Linux with multiple pipes in C?

I am writing a C program which runs the following Linux command with multiple pipes:

cat myfile1.txt | egrep Computing | wc -l > myfile

My code is as follows:

    int p_fd[2];
    pid_t childpid, waitReturn;
    int pid=1;
    int status, i;

    pipe(p_fd);

    for( i = 1 ; i < 3 ; i++ )
        if( childpid = fork() )
            break;
        else
            pid++;

    while( childpid != ( waitReturn = wait( &status ) ) )
        if( ( waitReturn == -1 ) && ( errno != EINTR ) )
            break;

    if ( childpid > 0 && pid == 1 ){
        printf("%d\n", pid);
        int fd;
        if ( ( fd= open("myfile", O_CREAT|O_RDWR|O_TRUNC, 00644)) == -1 )
        {
                printf("Error: Cannot open file in open()\n");
                exit(1);
        }
        close(0);
        dup(p_fd[0]);
        close(1);
        dup(fd);
        close(p_fd[0]);
        close(p_fd[1]);
        close(fd);
        execl("/bin/wc", "wc", "-l", NULL);
    }else if( childpid > 0 && pid == 2 ){
        printf("%d\n", pid);
        close(0);
        dup(p_fd[0]);
        close(1);
        dup(p_fd[1]);
        close(p_fd[0]);
        close(p_fd[1]);

        execl("/bin/egrep", "egrep", "Computing", NULL);

    }else if( childpid == 0 && pid == 3 ){
        printf("%d\n", pid);
        close(1);
        dup(p_fd[1]);
        close(p_fd[0]);
        close(p_fd[1]);

        execl("/bin/cat", "cat", "myfile1.txt", NULL);
    }   

    return 0;

However, my program hangs when it reaches "execl("/bin/egrep", "egrep", "Computing", NULL);", which is called in the second child with a pid 2.

I do not know the reason why my program hangs there; is it about the pipe's deadlock?

Would anyone could help me to modify the above program so that it can give me the desired result?

How about something like the following pseudo code:

create_pipe_between_cat_and_egrep();
create_pipe_between_egrep_and_wc();
create_destination_file();

if (fork() == 0)
{
    /* Process for cat */
    setup_pipe_stdout_for_cat();
    execl("cat", "cat", "arguments");
}

if (fork() == 0)
{
    /* process for egrep */
    setup_pipe_stdin_stdout_for_egrep();
    execl("egrep", "egrep", "arguments");
}

if (fork() == 0)
{
    /* process for wc */
    setup_pipe_stdin_for_wc();
    setup_file_stdout_for_wc();
    execl("wc", "wc", "arguments");
}

wait_for_all_three_child_processes_to_finish();

It's easier to follow the flow with three distinct blocks like above, instead of a loop.

Much of the code can be put in generic functions, like setting up the stdin / stdout descriptors for the child processes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM