How to pipe stderr without piping stdout
How do I pipe the standard error stream without piping the standard out stream?
I know this command works, but it also writes the standard out.
Command 2>&1 | tee -a $LOG
How do I get just the standard error?
Note: What I want out of this is to just write the stderr stream to a log and write both stderr and stdout to the console.
To do that, use one extra file descriptor to switch stderr and stdout:
find /var/log 3>&1 1>&2 2>&3 | tee foo.file
Basically, it works, or at least I think it works, as follows:
The re-directions are evaluated left-to-right.
3>&1
Makes a new file descriptor, 3 a duplicate (copy) of fd 1 (stdout).
1>&2
Make stdout (1) a duplicate of fd 2 (stderr)
2>&3
Make fd 2, a duplicate (copy) of 3, which was previously made a copy of stdout.
So now stderr and stdout are switched.
| tee foo.file
tee duplicates file descriptor 1 which was made into stderr.
Kyle's Unix/Linux command does the job of switching the STDERR with the STDOUT; however the explanation is not quite right. The redirecting operators do not do any copying or duplicating, they just redirect the flow to a different direction.
Rewriting Kyle's command by temporary moving the 3>&1 to the end, would make it easier to understand the concept:
find /var/log 1>&2 2>&3 3>&1
Written this way though, Linux would display an error because &3 does not exist yet as it is located before 3>&1. 3>something is a way to declare (define) that we are going to use a third pipe, so it has to be located before we flow water into that pipe, for instance the way Kyle wrote it. Try this other way just for fun:
((echo "STD1"; anyerror "bbbb"; echo "STD2" ) 3>&1 4>&2 1>&4 2>&3) > newSTDOUT 2> newSTDERR
Not having a way to do copies is a shame. You cannot do things like "3>&1 3>&2" in the same command, because Linux will only use the first one found and dismisses the second.
I have not (yet) found a way to send both the error and the regular output to a file and also send a copy of the error to the standar output with one command. For instace, I have a cron job that I want both outputs (error and standard) go to a log file and let the error also go out to make an email message sent to my blackBerry. I can do it with two commands using "tee" but the error does not show in the right order among the regular output line in the file. This is the ugly way I resolved the problem:
((echo "STD1"; sdfr "bbbb"; echo "STD2" ) 3>&1 1>&2 2>&3 | tee -a log1 ) 2>> log1
Note that I have to use log1 twice and I have to append in both cases, the firs one using the "-a" option for the "tee" command and the second one using ">>".
Doing a cat log1 you get the following:
STD1
STD2
-bash: sdfr: command not found
Notice that the error does not show in the second line as it should.
according to the man page for ksh (pdksh), you can just do:
Command 2>&1 >/dev/null | cat -n
i.e. dup stderr to stdout, redirect stdout to /dev/null, then pipe into 'cat -n'
works on pdksh on my system:
$ errorecho(){ echo "$@" >&2;} $ errorecho foo foo $ errorecho foo >/dev/null # should still display even with stdout redirected foo $ errorecho foo 2>&1 >/dev/null | cat -n 1 foo $