29

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.

4 Answers 4

29

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.

5
  • Oh, not tested with ksh, works with bash though ... Sep 9, 2009 at 13:00
  • Thanks, works in ksh too. I think most of the pipe and stream things are posix standard.
    – C. Ross
    Sep 9, 2009 at 13:14
  • "Copy" isn't really correct -- See @Guasqueño's Answer. Nov 19, 2010 at 20:33
  • This also works in Windows with tee.exe installed :)
    – Acorn
    Mar 21, 2011 at 22:46
  • Awesome! Exactly what I needed.
    – barakbd
    May 15, 2020 at 1:24
14

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.

2
  • Awesome correction! Nov 19, 2010 at 20:32
  • Check out zsh and mult_ios option (on by default) to be able to redirect a FD multiple times.
    – Tom Hale
    Jun 29, 2018 at 10:32
4

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
$   
1
  • Works with BusyBox too
    – Udo G
    Jul 30, 2012 at 15:48
1

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.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .