When you want to pipe only STDERR, you probably want to filter STDERR somehow, perhaps using grep or awk or sed, but you don't want to damage the output on STDOUT.
Suppose, for example, that you have a program which produces nice output, but also generates errors on STDERR. Of those errors, there are a few you're interested in, but most simply clutter the output. So you want to filter the STDERR output, but preserve the STDOUT output.
We all know we can redirect STDERR to STDOUT with the syntax
# some_program 2>&1but this would simply merge STDOUT and STDERR, so downstream you wouldn't know which what was an error and what was plain old output. In bash, you cannot pipe STDERR directly like you can in csh. Instead, you need to flip STDERR and STDOUT, do your filtering, then flip them back.
Before I show you the command, keep in mind two things:
2. You can only pipe or redirect for the command you're in. So
# echo BOB ; echo DAN > /dev/nulldoesn't make BOB disappear. It just makes DAN disappear.
OK. So how do we do this? Well, to flip #2 and #1, we use the trick
3>&1 1>&2 2>&3This creates an entirely new output memory location called #3, and copies the file descriptor of #1 into it. It then puts the file descriptor of #2 in #1. Lastly, it puts the file descriptor of #3 in #2. The order of operations is important. We need to save #1 before we redirect it, and we need make #1 a copy of #2 before we make #2 a copy of #3. Any difference in the order would send the same thing to two places.
The exact same sequence flips them back.
# tar -cf /tmp/junk.tar /tmp/real /tmp/fake tar: Removing leading `/' from member names tar: /tmp/fake: Cannot stat: No such file or directory tar: Error exit delayed from previous errors
The directory /tmp/real exists, but the directory /tmp/fake doesn't. The other messages are things we always see. We'd rather only see the message about /tmp/fake. We do this using egrep.
# tar -cf /tmp/junk.tar /tmp/real /tmp/fake 3>&1 1>&2 2>&3 | egrep -v "tar: Removing leading|tar: Error exit delayed from previous errors" tar: /tmp/fake: Cannot stat: No such file or directory
Better. But STDERR is now on STDOUT and vice versa. We should flip them back. And here's where my second point from above comes in. You can't just add the flipping syntax at the end of the egrep command. The egrep command has it's own STDERR location, distinct from the one tar is using. You need to bunch them together before flipping them back. You do this by using parenthesis.
# (tar -cf /tmp/junk.tar /tmp/real /tmp/fake 3>&1 1>&2 2>&3 | egrep -v "tar: Removing leading|tar: Error exit delayed from previous errors") 3>&1 1>&2 2>&3 tar: /tmp/fake: Cannot stat: No such file or directory
Yes, it's a mess. But now that you have the pattern, you can use it
when you really need it. For example, when you only want to see
certain types of STDERR output in cron jobs. You can put the above
syntax in lines of your crontab, or you can wrap your commands in
scripts, so as not to junk up your crontab file.
( COMMAND 3>&1 1>&2 2>&3 | grep -v ANNOYING_ERRORS ) 3>&1 1>&2 2>&3 | grep TARGET_STRINGS