Home > Back-end >  How do I get both STDOUT and STDERR to go to the terminal and a log file - and preserve stdout/stder
How do I get both STDOUT and STDERR to go to the terminal and a log file - and preserve stdout/stder

Time:12-07

This is a follow-up to this question:

How do I get both STDOUT and STDERR to go to the terminal and a log file?

In short: I want to run a command and store both, STDOUT and STDERR in one log file (to keep time correlation) but I need STDERR output still to be printed on STDERR.

Motivation: there are tools which run a command and treat STDOUT and STDERR differently - e.g. printing STDERR in a different color or print STDERR when the command returns non-zero.

So I'd like to have a way to store all output in one log file but preserve the distinction between STDOUT and STDERR (as well as the return code).

log-output --file=command.log -c "make stuff-with-stderr"

From what I found in the above links answers there are at least two different approaches:

the_cmd 1> >(tee stdout.txt ) 2> >(tee stderr.txt >&2 )

will store STDOUT and STDERR in separate files, thus loosing time correlation. And unfortunately both STDOUT and STDERR will be printed on STDOUT only.

script -e -B build.log -c "the_cmd"

will store both STDOUT and STDERR in one file, keeping time correlation but still prints both STDOUT and STDERR on on STDOUT only.

So none of those approaches meets my requirements. Is there something else?

CodePudding user response:

Edit:

Using my approach and your command from the comment below (pip3 install -U pytest) in a bash shell you get your desired outcome:

(((pip3 install -U pytest | tee -a log.txt) 3>&1 1>&2 2>&3 | tee -a log.txt) 3>&1 1>&2 2>&3)

The entries in log.txt are always in the correct order (same as executing pip3 install -U pytest in a terminal) and the output is printed to the terminal correctly (separate streams for stdout and stderr). I suspect a better solution exists, but this appears to be a 'workable' solution to the problem.


Original answer:

There's probably a less awkward solution than this, but you could tee stdout to log.txt, then swap stdout with stderr and tee the 'new' stdout (stderr) to log.txt, then swap stderr back with stdout, then print both streams to terminal (similar to the example here):

((({ echo "test_out"; echo "test_err" 1>&2; } | tee -a log.txt) 3>&1 1>&2 2>&3 | tee -a log.txt) 3>&1 1>&2 2>&3)
test_out
test_err

cat log.txt
test_out
test_err

# show stdout/stderr are still separate streams:
((({ echo "test_out"; echo "test_err" 1>&2; } | tee -a log.txt) 3>&1 1>&2 2>&3 | tee -a log.txt) 3>&1 1>&2 2>&3) 1>std.out 2>std.err

cat std.out
test_out

cat std.err
test_err
  • Related