Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Shell implement pipe programmatically?

Tags:

linux

I understand how I/O redirection works in Unix/Linux, and I know Shell uses this feature to pipeline programs with a special type of file - anonymous pipe. But I'd like to know the details of how Shell implements it programmatically? I'm interested in not only the system calls involved, but also the whole picture.

For example ls | sort, how does Shell perform I/O redirection for ls and sort?

like image 837
Dagang Avatar asked Sep 20 '25 14:09

Dagang


2 Answers

The whole picture is complex and the best way to understand is to study a small shell. For a limited picture, here goes. Before doing anything, the shell parses the whole command line so it knows exactly how to chain processes. Let's say it encounters proc1 | proc2.

  • It sets up a pipe. Long story short, writing into thepipe[0] ends up in thepipe[1]

    int thepipe[2];
    pipe(thepipe);
    
  • It forks the first process and changes the direction of its stdout before exec

    dup2 (thepipe[1], STDOUT_FILENO);
    
  • It execs the new program which is blissfully unaware of redirections and just writes to stdout like a well-behaved process

  • It forks the second process and changes the source of its stdin before exec

    dup2 (thepipe[0], STDIN_FILENO);
    
  • It execs the new program, which is unaware its input comes from another program

Like I said, this is a limited picture. In a real picture the shell daisy-chains these in a loop and also remembers to close pipe ends at opportune moments.

like image 116
cnicutar Avatar answered Sep 23 '25 10:09

cnicutar


This is a sample program from the book operating system concepts by silberschatz

Program is self-explanatory if you know the concepts of fork() and related things..hope this helps! (If you still want an explanation then I can explain it!)

Obviously some changes(such as change in fork() etc) should be made in this program if you want it to make it work like

ls | sort

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

    #define BUFFER SIZE 25
    #define READ END 0
    #define WRITE END 1
    int main(void)
    {
    char write msg[BUFFER SIZE] = "Greetings";
    char read msg[BUFFER SIZE];
    int fd[2];
    pid t pid;

    /* create the pipe */
    if (pipe(fd) == -1) {
    fprintf(stderr,"Pipe failed");
    return 1;
    }
    /* fork a child process */
    pid = fork();
    if (pid < 0) { /* error occurred */
    fprintf(stderr, "Fork Failed");
    return 1;
    }
    if (pid > 0) { /* parent process */
    /* close the unused end of the pipe */
    close(fd[READ END]);
    /* write to the pipe */
    write(fd[WRITE END], write msg, strlen(write msg)+1);
    /* close the write end of the pipe */
    close(fd[WRITE END]);
    }
    else { /* child process */
    /* close the unused end of the pipe */
    close(fd[WRITE END]);
    /* read from the pipe */
    read(fd[READ END], read msg, BUFFER SIZE);
    printf("read %s",read msg);
    }
    }
    /* close the write end of the pipe */
    close(fd[READ END]);
    return 0;
    }
like image 38
Nullpointer Avatar answered Sep 23 '25 10:09

Nullpointer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!