There are several ways of redirecting the output of a child process:
freopen(3)
dup(3)
popen(3)
You can discover what your favorite shell uses by strace(1)
ing your shell.
In one terminal:
echo $$
In another terminal:
strace -o /tmp/shell -f -p [PID from the first shell]
In the first terminal again:
ls > files.txt
In the second terminal, ^C
your strace(1)
command and then edit the /tmp/shell
output file to see what system calls it made to do the redirection.
freopen(3)
manipulates the C standard IO FILE*
pointers. All this will be thrown away on the other side of the execve(2)
call, because it is maintained in user memory. You could use this after the execve(2)
call, but that would be awkward to use generically.
popen(3)
opens a single unidirectional pipe(7)
. This is useful, but extremely limited -- you get either the standard output descriptor or the standard input descriptor. This would fail for something like ls | grep foo | sort
where both input and output must be redirected. So this is a poor choice.
dup2(2)
will manage file descriptors -- a kernel-implemented resource -- so it will persist across execve(2)
calls and you can set up as many file descriptors as you need, which is nice for ls > /tmp/output 2> /tmp/error
or handling both input and output: ls | sort | uniq
.
There is another mechanism: pty(7)
handling. The forkpty(3)
, openpty(3)
, functions can manage a new pseudo-terminal device created specifically to handle another program. The Advanced Programming in the Unix Environment, 2nd edition book has a very nice pty
example program in its source code, though if you're having trouble understanding why this would be useful, take a look at the script(1)
program -- it creates a new pseudo-terminal and uses it to record all input and output to and from programs and stores the transcript to a file for later playback or documentation. You can also use it to script actions in interactive programs, similar to expect(1)
.
I would expect to find dup2()
used mainly.
Neither popen()
nor freopen()
is designed to handle redirections such as 3>&7
. Up to a point, dup()
could be used, but the 3>&7
example shows where dup()
starts to creak; you'd have to ensure that file descriptors 4, 5, and 6 are open (and 7 is not) before it would handle what dup2()
would do without fuss.