Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

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.

share|improve this question
add comment

4 Answers

up vote 16 down vote accepted

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.

share|improve this answer
    
Oh, not tested with ksh, works with bash though ... –  Kyle Brandt Sep 9 '09 at 13:00
    
Thanks, works in ksh too. I think most of the pipe and stream things are posix standard. –  C. Ross Sep 9 '09 at 13:14
    
"Copy" isn't really correct -- See @Guasqueño's Answer. –  Kyle Brandt Nov 19 '10 at 20:33
    
This also works in Windows with tee.exe installed :) –  Acorn Mar 21 '11 at 22:46
add comment

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
$   
share|improve this answer
    
Works with BusyBox too –  Udo G Jul 30 '12 at 15:48
add comment

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.

share|improve this answer
    
Awesome correction! –  Kyle Brandt Nov 19 '10 at 20:32
add comment

i got it running like u ever wanted since i also needed it and refined your command. now for me it works correct using bash 3.2 on debian squeeze using this

(echo "foo" 3>&1 1>&2 2>&3 | tee -a log1 ) 2>> log1 >> log2

whereas log1 logs stdout and stderr and log2 only logs stderr and nothing else it put to screen.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.