You need to swap STDERR and STDOUT so you can send STDOUT to a logfile, but then send STDERR to the screen and to a file using the tee command. But pipes only work with STDOUT.
Swap STDERR and STDOUT before the pipe redirection using a third file descriptor:
$ ./myscript 3>&1 1>stdout.logfile 2>&3- | tee -a stderr.logfile
Whenever you redirect file descriptors, you are duplicating the open descriptor to another descriptor. This gives you a way to swap descriptors, much like how any program swaps two values—by means of a third, temporary holder. It looks like: copy A into C, copy B into A, copy C into B and then you have swapped the values of A and B. For file descriptors, it looks like this:
$ ./myscript 3>&1 1>&2 2>&3
Read the syntax 3>&1
as
“give file descriptor 3 the same value as output file descriptor 1.”
What happens here is that it duplicates file descriptor 1 (i.e., STDOUT)
into file descriptor 3, our temporary holding place. Then it duplicates
file descriptor 2 (i.e., STDERR
) into
STDOUT
, and finally duplicates file
descriptor 3 into STDERR. The net effect is that STDERR
and STDOUT
file descriptors have swapped
places.
So far so good. Now we just change this slightly. Once we’ve made
the copy of STDOUT
(into file
descriptor 3), we are free to redirect STDOUT
into the logfile we want to have
capture the output of our script or other program. Then we can copy the
file descriptor from its temporary holding place (fd 3) into STDERR.
Adding the pipe will now work because the pipe connects to the
(original) STDOUT
. That gets us to
the solution we wrote above:
$ ./myscript 3>&1 1>stdout.logfile 2>&3- | tee -a stderr.logfile
Note the trailing -on the 2>&3-
term. We do that so that we close
file descriptor 3 when we are done with it. That way our program doesn’t
have an extra open file descriptor. We are tidying up after
ourselves.
Linux Server Hacks, First Edition, hack #5 “n>&m: Swap STDOUT and STDERR,” by Rob Flickenger (O’Reilly)
18.217.150.123