I want to redirect stdout and stderr to a file while preserving the order of output but then also show stderr to screen. I see a lot of questions discuss it:
But none of them seem to do what I want or preserve the order.
My test script:
#!/bin/bash
echo "1: good" >&1
echo "2: error" >&2
echo "3: error" >&2
echo "4: good" >&1
echo "5: error" >&2
echo "6: good" >&1
echo "7: error" >&2
echo "8: good" >&1
echo "9: error" >&2
What I have so far:
$ ./test.sh 2>&1 > output.log
Standard UNIX semantics do not permit this; it cannot be reliably done using only facilities built into bash or specified in POSIX.
Writes only have a guaranteed order in relation to each other when they happen to the same destination. As soon as you redirect stdout and stderr to different destinations, the operating system no longer offers guarantees around ordering of writes performed to them; doubly when those writes are to a separate process (such as tee
) which then must read content and perform its own further writes, subject to OS-level scheduling.
It may be possible to use syscall-level tracing facilities provided by (or available for) your operating system to generate an absolute ordering of system calls, and thus to generate definitively-ordered output; an example of this is given in the answer to Separately redirecting and recombining stderr/stdout without losing ordering.
Using bash itself, however, you can only control where file descriptors of a subprocess are connected, and not how content written to those descriptors is buffered and flushed, so there simply isn't enough control to make what you're asking for possible without writes being subject to reordering.