Open files are inherited across an exec() unless you explicitly tell the file descriptors to “close on exec.” This behavior forms the basis of building pipelines between programs. A process calls pipe() to create a communications channel before fork()ing:
int pipe (int fildes);
pipe() fills the filedes array with two file descriptors that are connected in such a way that data written to filedes can be read from filedes. If you wanted to fork() and exec() a command and read that command’s output, you would do something like this, as illustrated in Figure 18.5:
Create the pipe
The child uses dup2() to move filedes to standard out.
The child exec()s a program.
The parent reads the program’s output from filedes. After ...