Matthias Benkmann mbenkmann at gmx.de
Thu Dec 28 12:33:06 PST 2000

> On Thursday 28 December 2000 09:29, Matthias Benkmann wrote:
> > { command 3>&1 4>&2 1>&4 2>&3 | tee error.log ; } 2>&1 |tee main.log
> >
> > This sends stdout+stderr to the screen and into main.log. stderr alone is
> > sent to error.log.
> >
> > If you don't need it to go on screen, you can use
> >
> > { command 3>&1 4>&2 1>&4 2>&3 | tee error.log ; } 2>&1 main.log
> >
> > I agree it's a bit complicated but I guess you can wrap it in a shell
> > function.
> Could you explain it a bit please? I spent a fair amout of time trying to 
> construct something like this, but I figured it must have been impossible. I 
> don't understand your redirections. How do you invert the stderror and stdout?

The basic problem to be solved is that "|" only works on stdout, meaning 
that you can only use "tee" to fork off stdout to a separate file.

command | tee stdout.log

will send stdout+stderr to screen and a copy of stdout to stdout.log

{ command | tee stdout.log ; } 2>&1 main.log

will capture the stdout+stderr output in main.log (the braces are just for 
grouping so that the redirection can be applied to the whole command).
If you also want it on screen, you use "tee" again and you get

{ command | tee stdout.log ; } 2>&1 | tee main.log

Okay, so far so good. Now we don't want want stdout.log, we want 
stderr.log. We would need a  "2|" operator that does the same as "|" but 
uses stderr instead of stdout. AFAIK, that one doesn't exist. So we use a 
trick. We "simply" swap stdout and stderr. How to do this becomes clear 
when you realize that you're simply dealing with file descriptors. 1 is 
the fd for stdout, 2 is the fd for stderr. 

x >& y 

makes the file descriptor x become a copy of the file descriptor y.
That's why 

command >main.log 2>&1  

("2>&1" can be abbreviated ">&")

will send stdout+stderr to main.log. You have to read it from left to 
right. First the file descriptor for stdout is made to refer to the file 
main.log. Next, the file descriptor for stderr (.i.e number 2) is made a 
copy of stdout's fd. This means that stderr will also refer to main.log, 
i.e. it will write to the same file.
This is also the reason why

command 2>&1 >main.log 

will *NOT* work. It makes stderr become a copy of stdout first, which is 
completely redundant as they start out like this. Then it makes stdout 
refer to main.log without touching stderr. So the result is the same as 
doing just

command >main.log

The next thing you have to realize is that there are many more file 
descriptors than just stdin,stdout,stderr. Bash doesn't prevent you from 
referring to file descriptor 3,4,5,... and this is how you can swap stdout 
and stderr. 

3>&1 4>&2 

will make fd 3 a copy of fd 1 and fd 4 a copy of fd 2. 

1>&4 2>&3

will make fd 1 a copy of fd 4 (which is a copy of the original fd 
2=stderr) and fd 2 a copy of fd 3 (which is a copy of the original fd 
1=stdout). That way stderr and stdout are swapped.

I hope this helped explain redirections a bit and I hope that my construct 
actually works in all cases. I only tried it on a small shell function. 


If everything seems to be going well, you have obviously overlooked something.

Unsubscribe: send email to lfs-discuss-request at linuxfromscratch.org
and put unsubscribe in the subject header of the message

More information about the lfs-dev mailing list