43.3. Send (Only) Standard Error Down a Pipe
A vertical bar character (|) on a command line pipes the standard output of a process to another process. How can you pipe the standard error but not the standard output? You might want to put a long-running cruncher command in the background, save the output to a file, and mail yourself a copy of the errors. In the C shell, run the command in a subshell (Section 43.7). The standard output of the command is redirected inside the subshell. All that's left outside the subshell is the standard error; the |& operator (Section 43.5) redirects it (along with the empty standard output) to the mail (Section 1.21) program:
% (cruncher > outputfile) |& mail yourname &  12345
Of course, you don't need to put that job in the background. If you want the standard output to go to your terminal instead of a text file, use /dev/tty (Section 36.15) as the outputfile.
The Bourne shell gives you a lot more flexibility and lets you do just what you need. The disadvantage is the more complicated syntax (Section 36.16). Here's how to run your cruncher program, route the stderr through a pipe to the mail program, and leave stdout going to your screen:
$ (cruncher 3>&1 1>&2 2>&3 3>&-) | mail yourname & 12345
If this example makes your head hurt a little, you're not alone. The key to understanding this arcana is to know that programs don't refer to files by name like users do. Instead, when a program wants to read or write to a file, it must ask the operating system for a file stream that has an integer file descriptor associated with it. Every program has three file streams opened by default: standard input, standard output, and standard error. The file descriptors associated with standard input and standard error are 1 and 2, respectively. These file streams may be duplicated; that is, the data stream pointed by the file descriptor on the left will now go to data stream pointed to by the file descriptor on the right. If you wanted to redirect both standard error and standard output to more, you might do this:
$ command 2>&1 | more
To redirect stdout to an output file and send stderr down a pipe, try this:
$ (cruncher 3>&1 >outputfile 2>&3 3>&-) | mail yourname & 12345
Copyright © 2003 O'Reilly & Associates. All rights reserved.