简体   繁体   中英

c - Can't pipe three processes

I've been trying to implement the following command in c: cat /etc/passwd | cut –f1 –d: | sort

This is the code I've got so far. The first pipe works correctly but the second pipe doesn't seem to work at all.

I've checked the code over and over but can't see anything wrong. Can anyone provide a suggestion that will fix my problem?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
    {
        int pipe_A[2];
        int pipe_B[2];

        pipe(pipe_A);
        pipe(pipe_B);

        pid_t pid_A, pid_B, pid_C;

        if( !(pid_A = fork()) ) {
            close(1);       /* close normal stdout */
            dup(pipe_A[1]);   /* make stdout same as pipe_A[1] */
            close(pipe_A[0]); /* we don't need this */
            execlp("/bin/cat", "cat", "/etc/passwd" ,  NULL);
        }

        if( !(pid_B = fork()) ) {
            close(0);       /* close normal stdin */
            dup(pipe_A[0]);   /* make stdin same as pipe_A[0] */
            close(pipe_A[1]); /* we don't need this */

            close(1);   /* close normal stdout */
            dup(pipe_B[1]);   /* make stdout same as pipe_B[1] */
            close(pipe_B[0]); /* we don't need this */
            execlp("/usr/bin/cut", "cut", "-f1", "-d:", NULL);
       }

       if( !(pid_C = fork()) ) {
            close(0);       /* close normal stdin */
            dup(pipe_B[0]);   /* make stdin same as pipe_B[0] */
            close(pipe_B[1]); /* we don't need this */
            execlp("/usr/bin/sort", "sort", NULL);
       }

    return 0;
}

Thank you.

The problem is that you are leaking open FDs all around. Note that every time you call fork all the open pipes are inherited by the child process, but pipes with dup'ed FDs don't work properly.

For example, cat is inheriting both read and write FDs of pipe_B . Likewise, sort is inheriting both FDs of pipe_A .

The right way to go would be along the lines of (but I recommend to use dup2() instead):

int main(void)
{
    int pipe_A[2];
    int pipe_B[2];
    pid_t pid_A, pid_B, pid_C;

    pipe(pipe_A);

    if( !(pid_A = fork()) ) {
        close(pipe_A[0]); // A-read not needed here

        close(1);
        dup(pipe_A[1]);
        close(pipe_A[1]); //do not pass A-write twice

        execlp("/bin/cat", "cat", "/etc/passwd" ,  NULL);
    }

    close(pipe_A[1]); // A-write not needed anymore

    pipe(pipe_B); //do not create this pipe until needed

    if( !(pid_B = fork()) ) {
        close(pipe_B[0]); // B-read not needed here

        close(0);
        dup(pipe_A[0]);
        close(pipe_A[0]); //do not pass A-read twice


        close(1);
        dup(pipe_B[1]);
        close(pipe_B[1]); //do not pass B-write twice

        execlp("/usr/bin/cut", "cut", "-f1", "-d:", NULL);
   }
   close(pipe_A[0]); // A-read not needed anymore
   close(pipe_B[1]); // B-write not needed anymore

   if( !(pid_C = fork()) ) {

        close(0);
        dup(pipe_B[0]);
        close(pipe_B[0]); // do not pass B-read twice

        execlp("/usr/bin/sort", "sort", NULL);
   }
   close(pipe_B[0]); // B-read not needed anymore
   return 0;
}

If you analyze my code (and if I wrote it right), assuming that the parent process has only FDs 0, 1 and 2, every single execlp() will get exactly 3 FDs, 0, 1 and 2.

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