-
Notifications
You must be signed in to change notification settings - Fork 326
How Unix Pipes are Implemented
Brian "Beej Jorgensen" Hall edited this page Jun 29, 2018
·
4 revisions
In the shell, you can do something like
ls -la / | wc
The pipe |
symbol says "let's take the output from ls -la /
and pipe it into the input of wc
. (wc
is "word count"--tells you how many characters, words, and lines its input has.)
Steps are:
- Create a pipe with
pipe()
. - Fork a child process to run
wc
. (The parent process will runls -la /
.) - In the child:
- Use
dup2()
to hook file descriptor0
(stdin
) up to the "read" end of the pipefd[0]
. This makes it so that whenever the child process reads fromstdin
, it actually reads from the pipe. - Use
execlp()
to runwc
.wc
will read fromstdin
as per usual, but unbeknownst to it, we've hooked that up to the pipe.
- Use
- In the parent:
- Use
dup2()
to hook file descriptor1
(stdout
) up to the "write" end of the pipefd[1]
. This makes it so that whenever the parent process writes tostdout
, it actually writes into the pipe. - Use
execlp()
to runls -la /
.ls
will write tostdout
as per usual, but unbeknownst to it, we've hooked that up to the pipe.
- Use
That's it!
Source code:
/**
* Pipe example
*
* Runs the command: ls -la / | wc
*
* Try running the above command on the command line to see if the
* output matches.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int main(void)
{
int fd[2];
// Make the pipe for communication
pipe(fd);
// Fork a child process
pid_t pid = fork();
if (pid == -1) {
perror("fork");
exit(1);
}
if (pid == 0) {
// Child process
// Hook up standard input to the "read" end of the pipe
dup2(fd[0], 0);
// Close the "write" end of the pipe for the child.
// Parent still has it open; child doesn't need it.
close(fd[1]);
// Run "wc"
execlp("wc", "wc", NULL);
// We only get here if exec() fails
perror("exec wc");
exit(1);
} else {
// Parent process
// Hook up standard output to the "write" end of the pipe
dup2(fd[1], 1);
// Close the "read" end of the pipe for the parent.
// Child still has it open; parent doesn't need it.
close(fd[0]);
// Run "ls -la /"
execlp("ls", "ls", "-la", "/", NULL);
// We only get here if exec() fails
perror("exec ls");
exit(1);
}
return 0;
}