The C code here is used for reference of how to pipe 3 separate children processes. It can be improved to support a dynamic amount of processes and corresponding pipes and system calls.
// This program is an example of how to run a command such as // ps aux | grep root | grep sbin // using C and Unix. // pipe_example.c #include#include #include int pid; int pipe1[2]; int pipe2[2]; void exec1(); void exec2(); void exec3(); int main() { // create pipe1 if (pipe(pipe1) == -1) { perror("bad pipe1"); exit(1); } // create pipe2 if (pipe(pipe2) == -1) { perror("bad pipe2"); exit(1); } // fork (ps aux) if ((pid = fork()) == -1) { perror("bad fork1"); exit(1); } else if (pid == 0) { // stdin --> ps --> pipe1 exec1(); } // parent // fork (grep root) if ((pid = fork()) == -1) { perror("bad fork2"); exit(1); } else if (pid == 0) { // pipe1 --> grep --> pipe2 exec2(); } // parent // close unused fds close(pipe1[0]); close(pipe1[1]); // fork (grep sbin) if ((pid = fork()) == -1) { perror("bad fork3"); exit(1); } else if (pid == 0) { // pipe2 --> grep --> stdout exec3(); } // parent } void exec1() { // input from stdin (already done) // output to pipe1 dup2(pipe1[1], 1); // close fds close(pipe1[0]); close(pipe1[1]); // exec execlp("ls", "ls", NULL); // exec didn't work, exit perror("bad exec ls"); _exit(1); } void exec2() { // input from pipe1 dup2(pipe1[0], 0); // output to pipe2 dup2(pipe2[1], 1); // close fds close(pipe1[0]); close(pipe1[1]); close(pipe2[0]); close(pipe2[1]); // exec execlp("grep", "grep", "c", NULL); // exec didn't work, exit perror("bad exec grep c"); _exit(1); } void exec3() { // input from pipe2 dup2(pipe2[0], 0); // output to stdout (already done) // close fds close(pipe2[0]); close(pipe2[1]); // exec execlp("grep", "grep", "y", NULL); // exec didn't work, exit perror("bad exec grep y"); _exit(1); }
This code also works on Unix/Mac.
Compile with gcc pipe_example.c -o pipe_example.o
Run with ./pipe_example.o