[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Unexpected behaviour when using process substitution with stdout and std
From: |
earnestly |
Subject: |
Unexpected behaviour when using process substitution with stdout and stderr |
Date: |
Sun, 11 Jul 2021 11:09:10 +0100 |
GNU bash, version 5.1.8(1)-release (x86_64-pc-linux-gnu)
I have attempted to use process substitution in order to feed the
output of a command into two filters, one for handling stdout and the
other for stderr.
Prior to this I was using POSIX sh and named pipes to achieve this but
decided to try bash with its >() and <() notation.
Perhaps I am misunderstanding how this works because I found them to be
unusable in this context.
What appears to be happening is that the output from standard error is
being mixed into the function handling standard out, even more
surprisingly that xtrace output is also being consumed and filtered as
well.
I don't quite know how to describe what's happening so I have provided a
small demonstration/reproducer instead:
#!/bin/bash --
generate() {
for ((i=0; i<10; ++i)); do
if ((RANDOM % 2)); then
printf 'generate to stdout\n'
else
printf 'generate to stderr\n' >&2
fi
done
}
stdout() {
local line
while read -r line; do
printf 'from stdout: %s\n' "$line"
done
}
stderr() {
local line
while read -r line; do
printf 'from stderr: %s\n' "$line"
done
}
# Using process substitution.
unexpected() {
# This is particularly dangerous when the script is executed under `bash -x'
# as the xtrace output is read as standard input to the `stdout' function.
generate > >(stdout) 2> >(stderr)
wait
# Example output:
# from stdout: generate to stdout
# from stdout: generate to stdout
# from stdout: from stderr: generate to stderr
# from stdout: from stderr: generate to stderr
# from stdout: from stderr: generate to stderr
# from stdout: generate to stdout
# from stdout: from stderr: generate to stderr
# from stdout: generate to stdout
# from stdout: from stderr: generate to stderr
# from stdout: from stderr: generate to stderr
}
# Using named pipes.
expected() {
mkfifo a b
trap 'rm a b' EXIT
generate > a 2> b &
stdout < a &
stderr < b &
wait
# Example output:
# from stdout: generate to stdout
# from stderr: generate to stderr
# from stdout: generate to stdout
# from stderr: generate to stderr
# from stdout: generate to stdout
# from stdout: generate to stdout
# from stderr: generate to stderr
# from stdout: generate to stdout
# from stdout: generate to stdout
# from stderr: generate to stderr
}
- Unexpected behaviour when using process substitution with stdout and stderr,
earnestly <=