How can I redirect stderr to a pipe?
A pipe can only carry stdout of a program. To pipe stderr through it, you need to redirect stderr to the same destination as stdout. Optionally you can close stdout or redirect it to /dev/null to only get stderr. Some sample code:
# - 'myprog' is an example for a program that outputs both, stdout and # stderr # - after the pipe I will just use a 'cat', of course you can put there # what you want # version 1: redirect stderr towards the pipe while stdout survives (both come # mixed) myprog 2>&1 | cat # version 2: redirect stderr towards the pipe without getting stdout (it's # redirected to /dev/null) myprog 2>&1 >/dev/null | cat #Note that '>/dev/null' comes after '2>&1', otherwise the stderr will also be directed to /dev/null # version 3: redirect stderr towards the pipe while the "original" stdout gets # closed myprog 2>&1 >&- | cat
One may also pipe stderr only but keep stdout intact (without a priori knowledge of where the script's output is going). This is a bit trickier.
This has an obvious application with eg. dialog, which draws (using ncurses) windows onto the screen to stdout, and returns output to stderr. This may be a little inconvenient, because it may lead to a necessary temporary file which we may like to evade. (Although this is not necessary -- see [#faq40 FAQ #40] for more examples of using dialog specifically!)
On [http://www.tldp.org/LDP/abs/html/io-redirection.html TLDP], I've found following trick:
# Redirecting only stderr to a pipe. exec 3>&1 # Save current "value" of stdout. ls -l /dev/fd/ 2>&1 >&3 3>&- | grep bad 3>&- # Close fd 3 for 'grep' and 'ls'. # ^^^^ ^^^^ exec 3>&- # Now close it for the remainder of the script. # Thanks, S.C.
The output of the ls command shows where each file descriptor points to.
The same can be done without exec:
{ ls -l /dev/fd/ 2>&1 1>&3 3>&- | grep bad 3>&-; } 3>&1
To show it as a dialog one-liner:
exec 3>&1 dialog --menu Title 0 0 0 FirstItem FirstDescription 2>&1 >&3 3>&- | sed 's/First/Only/' exec 3>&-
This will have the dialog window working properly, yet it will be the output of dialog (returned to stderr) being altered by the sed. Cheers.
A similar effect can be achieved with process substitution:
perl -e 'print "stdout\n"; warn "stderr\n"' 2> >(tr a-z A-Z)
This will pipe standard error through the tr command.