I often want to do this and am for /dev/stderr
, but there may be problems with this approach; for example, Nix build scripts give permission errors if they try to write to /dev/stdout
or /dev/stderr
.
After reusing this wheel several times, my current approach is to use a replacement process as follows:
myCmd 2> >(tee >(cat 1>&2))
Reading this from the outside in:
This will work myCmd
, leaving it stdout as it is. 2>
redirects stderr myCmd
to another destination; destination here >(tee >(cat 1>&2))
, which will lead to its forwarding to the tee >(cat 1>&2)
command.
The tee
command duplicates its input (in this case stderr myCmd
) to its stdout and to this destination. The destination is here >(cat 1>&2)
, which will result in the transfer of data to the command cat 1>&2
.
The cat
simply passes its input directly to standard output. 1>&2
redirects stdout to go to stderr.
Reading from the inside:
The cat 1>&2
command redirects its stdin to stderr, so >(cat 1>&2)
acts like /dev/stderr
.
Therefore, tee >(cat 1>&2)
duplicates its stdin on both stdout and stderr, acting like tee /dev/stderr
.
We use 2> >(tee >(cat 1>&2))
to get 2 copies of stderr: one on stdout and one on stderr.
We can use the copy on stdout as usual, for example, store it in a variable. We can leave a copy on stderr to print on the terminal.
We can combine this with other redirects if we like, for example
# Create FD 3 that can be used so stdout still comes through exec 3>&1