2009-04-26
A Bourne shell irritation: piping just stderr
I generally like the Bourne shell, but I will easily admit that it has a number of things that are less than ideal. One of those less than ideal things is a peculiar omission: you cannot easily redirect just standard error into a pipeline.
This sounds like a peculiar thing to want, but there are situations where you do need to process stderr separately; for example, you might need to timestamp all stderr output and log it. In a hypothetical shell with this feature you could have a 'timestamper' program and just write:
process |[2] timestamper >>error-log
In the Bourne shell, not so much. You can do it, but it is what you would call intricate:
exec 3>&1
process 2>&1 >&3 3>&- | timestamper >>error-log
What's going on here is that first we save a copy of the real stdout on file descriptor 3, and then in the command itself we:
- send stdout to the timestamper process (remember, pipelines are set up before redirection)
- redirect stderr to stdout, which is the pipeline
- redirect stdout to fd 3, which is our original stdout
- close fd 3 so that
processdoes not inherit a surprise file descriptor.
(We must save the original stdout separately via exec because
of the pipeline vs redirection timing issue; if we wrote 'process
3>&1 ...' we would be capturing the pipe'd stdout, not the
original stdout.)
(This incantation is not original to me; I've seen it written up elsewhere on the Internet, but I never really understood it until I wrote out everything here (sort of cf, especially the comment).)