I usually have the following: ./myscript > myfile.log 2>&1
I want to have stderr and stdout to be written to myfile.log as well as have stderr to go "stderr" (terminal).
I was looking at tee, but tee is only for stdout.
CodePudding user response:
You can use tee
:
{ ./myscript 2>&1 >&3 | tee /dev/stderr >&3; } 3> myfile.out
or
{ ./myscript 2>&1 >&3 | tee /dev/fd/2 >&3; } 3> myfile.out
You might also try:
rm myfile.out; { ./myscript 2>&1 >&3 | tee -a myfile.out >&2; } 3>> myfile.out
but that feels a bit kludgy. I believe this should work as well:
{ ./myscript 2>&1 >&3 | tee -a myfile.out >&2; } 3> myfile.out
and feels slightly less like a kludge.
CodePudding user response:
Try it this way:
$: ./myscript 2> >( tee myfile.log >&2 ) 1>&2
Note the space between 2>
and >(
is required to keep the syntax unambiguous.
To prove it works as intended, put a filter on with grep
.
(I used ls
as a simple way to get output on both streams.)
$: ls -ld . bogus 2> >( tee err.log >&2 ) 1>&2 | grep foo >stdout.log
ls: cannot access 'bogus': No such file or directory
drwxr-xr-x 1 P2759474 1049089 0 Dec 15 11:19 .
Output from tee
sent to err.log
and to console stream 2, or stderr
. Stream 1 (stdout
) sent wherever stream 2 went, so also to tee
, which sends all it's output to its own stream 2, the stderr
of the console.
grep
couldn't see either, because nothing comes through on stream 1, so it can't filter non-matching lines.
$: ls -l err.log stdout.log
-rw-r--r-- 1 P2759474 1049089 113 Dec 15 11:19 err.log
-rw-r--r-- 1 P2759474 1049089 0 Dec 15 11:19 stdout.log
Everything went to tee
's log, nothing to grep
's.
$: cat err.log
ls: cannot access 'bogus': No such file or directory
drwxr-xr-x 1 P2759474 1049089 0 Dec 15 11:19 .