I have a process that generates output both on stderr
and stdout
.
I need to pipe these two different commands, but I would also like to keep seeing them on the terminal.
So I tried something like this as a proof of concept:
#!/usr/bin/env bash
set -e
function generate_output() {
echo This message goes to stderr 1>&2
echo This message goes to stdout
}
generate_output \
1> >(tee <&0 >(cat > out.log)) \
2> >(tee <&0 >(cat > err.log))
cat > out.log
is a dummy command that will be replaced by something else when I figure out how to make this work.
It almost works :
$ cat err.log
This message goes to stderr
And I see the output on the terminal.
So far so good !
But :
$ cat out.log
This message goes to stdout
This message goes to stderr
Why does the "stderr" message ends up in out.log ?
What puzzles me even more is that if I remove the tee command, the log file contain the expected result (but then I loose terminal output)
#!/usr/bin/env bash
set -e
function generate_output() {
echo This message goes to stderr 1>&2
echo This message goes to stdout
}
generate_output \
1> >(cat > out.log) \
2> >(cat > err.log)
Both tee
s are writing to stdout. That's fine for the first one but a problem for the second one since when the 2>
redirection is processed 1>
has already redirected stdout. That means that the second tee
isn't writing to the terminal, but to the first tee
process. Oops!
An elegant way to fix it is to have each of the tee
s write to the fd that they're reading from. Adding >&2
to the second one will fix the problem. And since I can tell you like parallel structure, you can add an explicit >&1
to the first one as well.
This will have the nice effect of preserving the separation of stdout and stderr in case there are any downstream consumers of your script's output.
generate_output \
1> >(tee <&0 >(cat > out.log) >&1) \
2> >(tee <&0 >(cat > err.log) >&2)
You can then eliminate some redundancies:
<&0
redirects stdin into stdin, which does nothing.>(cat >file)
is a complicated way of writing file
. You can get the same effect just by passing out.log
and err.log
directly to tee
.generate_output \
1> >(tee out.log >&1) \
2> >(tee err.log >&2)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With