0

I have scripts which write text (stdout) and error-messages (stderr) - and both I want to save to log files. The order of stdout and stderr must be preserved! But during runtime - I'm only interested in the printed text (stdout).

There are different solutions, e.g.:

bash script.sh 2>&1 >> out.log | tee -a out.log

...but I found none which preserves the order or stdout and stderr...

This is the myscript.sh which I used for testing:

#!/bin/sh
echo out1
echo err1 >&2
echo out2
echo err2 >&2
echo out3
echo err3 >&2
echo out4
echo err4 >&2
exit 7

The only way I know to get stdout and stderr written in the correct order to a file is &> - is there a way to dupplicate stdout before?

Imaging 1>&3 would dupplicate stdout to fd3 - instead of redirecting - this would be the idea:

./myscript.sh 1>&3 &>logfile 3>&1

PS: I'm using dash by default - bash would be OK too.

Charly
  • 1,270
  • 19
  • 42
  • 1
    Stdio implementations alter their buffering behavior according to whether their output is a terminal or not. The only way to preserve the order would be to run within a separate pseudo-terminal and capture the output of that terminal. – Petr Skocik Mar 27 '20 at 11:22
  • @PSkocik, how does the separate-pty approach allow stdout and stderr to be distinguished? If you're routing through `tee` to log content to stderr or stdout before *getting to* the pty, you're back in the same problem space. – Charles Duffy Mar 27 '20 at 16:09
  • *All* redirections duplicate the file descriptor -- they make the destination FD a copy of the original one, and thus cause it to write to the original FD's destination. That's the only kind of duplication that UNIX filesystem semantics allow; you fundamentally can't have a single `write()` going to more than one destination without having something `read()` it and then do one additional per-destination `write()`... thus introducing the synchronization problem that those additional writes are happening *after* the original, "real" one did. – Charles Duffy Mar 27 '20 at 16:12
  • You may want to look at this: https://stackoverflow.com/questions/45760692/separately-redirecting-and-recombining-stderr-stdout-without-losing-ordering?noredirect=1&lq=1 – Lenna Mar 27 '20 at 17:00

1 Answers1

0
  1. Brute force solution. Run the process twice.
./myscript.sh &> out.log & # Output stdout and stderr in correct order to log file
./myscript.sh 2> /dev/null # View stdout on terminal

Or a oneliner:

./myscript.sh &> out.log | ./myscript.sh 2>/dev/null
  1. Another brute force solution; Simply put time stamps on the output messages and redirect stdout and stderr to separate files to be merged together at a later time.
    Use this script to generate the two logfiles:
    ./myscript.sh > >(tee -a stdout.log) 2> stderr.log

You may want to take a look at This post for some ugly hackery

Lenna
  • 1,220
  • 6
  • 22