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