On Wed, 12 Jan 2011, Josh Trutwin wrote:

> Curious if anyone can help me with this - I have a long running script 
> and I'd like to redirect both stdout and stderr to a log file, as well 
> as have the output visible on the console (that last part I could live 
> without - just run a tail -f after execution).
>
> I've tried both of these after googling around:
>
> ./prog.sh 2>&1 | tee prog.log
> ./prog.sh 3>&1 >&2 2>&3 3>&- | tee prog.log
>
> Neither works - not sure if they aren't supported in /bin/bash.  Any 
> suggestions?


Funny thing -- I got really into this but was thinking you wanted stdout 
and stderr in two separate files, which is a lot harder, but it looks like 
I got that:

( ( ./prog.sh | tee prog.log.out ) 2>&1 1>&3 ) 3>&2 | tee prog.log.err


If you just want to put the stdout and stderr together, this works at 
least in recent-enough versions of bash:

./prog.sh 2>&1 | tee prog.log

But that's what you have above, so I think either you are not in a bash 
shell or you have an old bash version.  For me:

$ echo $BASH_VERSION
4.0.33(1)-release

And this works perfectly:

( echo "stdout1" ; echo "stderr1" 1>&2 ; echo stdout2 ) 2>&1 | tee foo.outerr


Regarding the system for keeping separate .out and .err files:  I find 
that the order of appearance on the terminal changes if the stderr and 
stdout are produced at almost the same time:

$ ( echo "stdout1" ; echo "stderr1" 1>&2 ; echo stdout2 )
stdout1
stderr1
stdout2

So stderr was second, but here it is first:


$ ( ( ( echo "stdout1" ; echo "stderr1" 1>&2 ; echo stdout2 ) | tee foo.out ) 2>&1 1>&3 ) 3>&2 | tee foo.err
stderr1
stdout1
stdout2

Adding a few milliseconds between makes it come out in order:

$ ( ( ( echo "stdout1" ; sleep .01 ; echo "stderr1" 1>&2 ; sleep .01 ; echo stdout2 ) | tee foo.out ) 2>&1 1>&3 ) 3>&2 | tee foo.err
stdout1
stderr1
stdout2

Best,
Mike