Skip to content

Instantly share code, notes, and snippets.

@mplewis
Created March 31, 2013 01:31
Show Gist options
  • Save mplewis/5279108 to your computer and use it in GitHub Desktop.
Save mplewis/5279108 to your computer and use it in GitHub Desktop.
Here's an example of how to pipe three commands together using C. This one uses `ps aux | grep root | grep sbin`. This topic is horribly documented online so hopefully this'll help someone else out.
// This program is an example of how to run a command such as
// ps aux | grep root | grep sbin
// using C and Unix.
#include <stdlib.h>
#include <unistd.h>
int pid;
int pipe1[2];
int pipe2[2];
void main() {
// create pipe1
if (pipe(pipe1) == -1) {
perror("bad pipe1");
exit(1);
}
// fork (ps aux)
if ((pid = fork()) == -1) {
perror("bad fork1");
exit(1);
} else if (pid == 0) {
// stdin --> ps --> pipe1
exec1();
}
// parent
// create pipe2
if (pipe(pipe2) == -1) {
perror("bad pipe2");
exit(1);
}
// 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("ps", "ps", "aux", NULL);
// exec didn't work, exit
perror("bad exec ps");
_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", "root", NULL);
// exec didn't work, exit
perror("bad exec grep root");
_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", "sbin", NULL);
// exec didn't work, exit
perror("bad exec grep sbin");
_exit(1);
}
@msabwat
Copy link

msabwat commented Jan 5, 2021

Thank you, this helped a lot :)

@wilschmidtt
Copy link

Thank you for this, it really makes the concept simple and understandable

@ElectricRCAircraftGuy
Copy link

ElectricRCAircraftGuy commented Mar 15, 2022

For additional help, an excellent example of pipes in C in Linux is here under the "EXAMPLES" section: https://man7.org/linux/man-pages/man2/pipe.2.html


Also, I can confirm that threePipeDemo.c does compile, contrary to what @nskoro says. Just make sure you do NOT use -Werror in your compile command, as there are a variety of warnings.

Here is my compile command. I tested this on Linux Ubuntu 18.04.

# compile
mkdir -p bin && gcc -Wall -Wextra -O3 -std=c17 threePipeDemo.c -o bin/a

# then run the program with:
bin/a 

Here's my compile command and the output with a bunch of warnings:

eRCaGuy_hello_world/c/todo$ mkdir -p bin && gcc -Wall -Wextra -O3 -std=c17 threePipeDemo.c -o bin/a
threePipeDemo.c:52:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]
 void main() {
      ^~~~
threePipeDemo.c: In function ‘main’:
threePipeDemo.c:56:5: warning: implicit declaration of function ‘perror’ [-Wimplicit-function-declaration]
     perror("bad pipe1");
     ^~~~~~
threePipeDemo.c:66:5: warning: implicit declaration of function ‘exec1’; did you mean ‘execl’? [-Wimplicit-function-declaration]
     exec1();
     ^~~~~
     execl
threePipeDemo.c:82:5: warning: implicit declaration of function ‘exec2’; did you mean ‘execl’? [-Wimplicit-function-declaration]
     exec2();
     ^~~~~
     execl
threePipeDemo.c:96:5: warning: implicit declaration of function ‘exec3’; did you mean ‘execl’? [-Wimplicit-function-declaration]
     exec3();
     ^~~~~
     execl
threePipeDemo.c: At top level:
threePipeDemo.c:104:6: warning: conflicting types for ‘exec1’
 void exec1() {
      ^~~~~
threePipeDemo.c:66:5: note: previous implicit declaration of ‘exec1’ was here
     exec1();
     ^~~~~
threePipeDemo.c:118:6: warning: conflicting types for ‘exec2’
 void exec2() {
      ^~~~~
threePipeDemo.c:82:5: note: previous implicit declaration of ‘exec2’ was here
     exec2();
     ^~~~~
threePipeDemo.c:135:6: warning: conflicting types for ‘exec3’
 void exec3() {
      ^~~~~
threePipeDemo.c:96:5: note: previous implicit declaration of ‘exec3’ was here
     exec3();
     ^~~~~

This is incredibly helpful for anyone trying to understand the super confusing execlp() cmd: I do not understand how execlp() works in Linux

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment