I am trying to add some information in front of every line output from a file, by:
Here is my test script:
#!/bin/bash
#
# Test proxying stdout and stderr
#
function proxy-stdouterr() {
local name="$1"
local handle=$2
while IFS='' read -r line
do
echo -e "[ ${name}: ${line} ]" >&${handle}
done
}
# Output some messages and attempt to parse them
(
echo "1: Normal message"
echo "2: Error" >&2
echo "3: Normal message"
echo "4: Error" >&2
) 2> >(proxy-stdouterr "stderr" 2) > >(proxy-stdouterr "stdout" 1)
This works fairly well but doesn't preserve the order in the terminal (Ubuntu 12.04).
When not proxying outputs:
1: Normal message
2: Error
3: Normal message
4: Error
However when proxying the order isn't kept. Worse this is not deterministic, most of the time it is:
[ stderr: 2: Error ]
[ stderr: 4: Error ]
[ stdout: 1: Normal message ]
[ stdout: 3: Normal message ]
But occasionally:
[ stderr: 2: Error ]
[ stdout: 1: Normal message ]
[ stderr: 4: Error ]
[ stdout: 3: Normal message ]
How can I fix this?
Thanks
As others noted, this is a synchronization problem with no obvious answer without knowing more about which parts you specifically control and want to change.
There are IMHO two main surfaces of attack:
stream buffering. Most C-derived programs do not buffer stderr,
buffer stdin and stdout by line if they're a terminal and buffer
them fully otherwise. This explains why stderr tends to always come
up first in your example. A cheap cop-out is to use /usr/bin/echo
instead of builtin echo
, so you'll get a flushed stream at the end
of every line (and a lot of delay for process spawning). It solves
your example 100% for what I've tried, so it could be enough for you
too. If you've got control on the command that generates the lines,
ensure both stdout and stderr are line-buffered.
process scheduling. You've got two processes competing to read from
both streams. Should there be data flowing on both at the time,
they're in a race against each other. You can mitigate that by
having a single process do that, but I'm not sure it's possible to
keep it efficient in native bash
(no programmable POSIX select
available to the end-user)
In any case, if there's queueing anywhere in the picture, you're screwed as far as keeping the order goes.
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