Using Advanced Redirection with stderr
Throughout this book, we've been redirecting input to output, piping the output of one command to the input of another, and generally getting fairly fancy. Can you believe that there's even more you can do with redirection?
Unix provides three channels (technically known as file descriptors) for communication between the user and the system:
Standard input (stdin), which refers to providing information at the shell prompt or accepting information from a different program.
Standard output (stdout), which refers to the output you see whirring by on your screen after you issue a commandfor example, if you issue the command find / -name test.
Standard error (stderr), which includes error messages you might see whir by on your screen after you issue a command. You might think of this channel as the "second" output channel.
Until now, you've been redirecting stdin and stdout with <, >, |, >>, and sometimes tee. Everything on stderr has just accompanied stdout. Adding separate redirection of stderr to your arsenal can make your Unix experience even more flexible.
To Redirect Stderr in zsh, bash, ksh, and Similar Shells:
time -p ls
Use the time utility, covered in Chapter 9, and note that you get both the output of ls and the output of time. As it happens,the output of time is on the stderr channel, although you'cant see that (the output all just shows up on the screen).
time -p ls 2> time-results.txt
Where you'd usually put a> to redirect everything to a file, use 2> to redirect the second output channel to a file. Now you'll get the output of ls on stdout on your screen, and the output of time, sent to stderr, in time-results.txt (Code Listing 17.9).
Code Listing 17.9. Redirecting standard output and standard error separately can be handy.
[jdoe@sulley Project]$ ls keep keeper.jpg kept kidder.txt kiddo kidnews kidneypie kids kidupdate [jdoe@sulley Project]$ time -p ls keep keeper.jpg kept kidder.txt kiddo kidnews kidneypie kids kidupdate real 0.00 user 0.00 sys 0.01 [jdoe@sulley Project]$ time -p ls 2> time-results.txt keep kept kiddo kidneypie kidupdate keeper.jpg kidder.txt kidnews kids time-results.txt [jdoe@sulley Project]$ time -p ls 1> /dev/null real 0.00 user 0.00 sys 0.00 [jdoe@sulley Project]$ time -p ls >/dev/null 2>&1 [jdoe@sulley Project]$
time -p ls 1> /dev/null
Or you can send the stdout to oblivion (/dev/null, which just throws it away) and get stderr on your screen.
time -p ls >/dev/null 2>&1
Or you can send the stderr to stdout, and stdout to oblivion. It's apparently pointless but useful in shell scripts if you care only to know whether something succeeded or failed.
If you're using zsh, you'll need to specify the full path to time (/usr/bin/time).time is a special zsh built-in command, so it works a bit differently from the other shells.
Redirecting stdout and stderr separately in csh is more challenging, but you can accomplish the same thing with time p ls >& /dev/null. This works in csh, bash, and zsh.
If you send both stderr and stdout to /dev/null, you can echo $? to find out whether your command succeeded. You'll get bonus points for being the first person who emails a valid original example of the value of this operation to firstname.lastname@example.org.