Swapping STDERR and STDOUT
Problem
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.
Solution
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
Discussion
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. ...
Get bash Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.