Search code examples
cpipeforkheredoc

how make cat and grep work in the first and the second pipe in c writing like heredoc in bash <<


I am working to make a shell like bash, but i have trouble solving heredoc << so i made a test code as simple as possible for this question.

        void pipeline()
    {
        int i = 0;
        int fd[2];
        pid_t pid;
        int fdd = 0;
    
        while (i < 2)
        {
            pipe(fd);
            pid = fork();
            if (pid == 0)
            {   
                //dup2(fd[1],1); if i dup in the first pipe cat dont finalize
                if (i == 0)
                    dup2(fd[0],0);
                write(fd[1], "hello\nhow\nare\nyou\n", 17);
                close(fd[0]);
                close(fd[1]);
                dup2(fdd, 0);
                if (i == 0)
                    execlp("cat", "cat", NULL);
                else
                    execlp("grep", "grep", "you" , NULL);
                perror("error");
                exit(1);
            }
            else 
            {   
                close(fd[1]);
                fdd = fd[0];
                wait(NULL);
                i++;
            }
        }
    }
    
    int main(int *argc, char **argv, char **env)
    {
        pipeline();
}

I know that cat and grep need an EOF to run; what I'm doing is writing in stdin and running cat, but my question is: how do I save stdout for grep without duping stdout on the first pipe?

If I dup on dup2(fd[1],1) cat does not work in the first pipe, could someone help me out to make this code work? And make it as similar to bash heredoc as well if possible.


Solution

  • how do I save stdout for grep without duping stdout on the first pipe?

    I'd rearrange the creation of the child processes from rightmost to leftmost - then grep is created first and can output to the initial output descriptor. A necessary change is to run all child processes before waiting on one as well as before writing, so that there's no deadlock even if the pipe buffer wouldn't suffice for the heredoc.

    void pipeline()
    {
        int i = 2;  // create children from last to first
        int fd[2];
        pid_t pid;
        int fdd = 1;    // output of last child is STDOUT
        while (i--)
        {
            pipe(fd);
            pid = fork();
            if (pid == 0)
            {
                dup2(fdd, 1);   // child's output
                dup2(fd[0], 0);
                close(fd[0]);
                close(fd[1]);
                if (i == 0)
                    execlp("cat", "cat", "-A", NULL);
                else
                    execlp("grep", "grep", "you" , NULL);
                perror("error");
                exit(1);
            }
            if (fdd != 1) close(fdd);   // close if a pipe write end
            fdd = fd[1];    // preceding child's output is pipe write end
            close(fd[0]);
        }
        write(fd[1], "hello\nhow\nare\nyou\n", 17);
        close(fd[1]);   // signal EOF to child
        while (wait(NULL) > 0) ;    // wait for all children
    }