Is this the best way to prefix all lines written by a Bash script to standard error?
#! /bin/bash
exec 3>&2
exec 2> >(sed 's/^/ERROR: /' >&3)
echo stdout
echo stderr >&2
I am wondering, if I have to close file descriptor 3.
There's not a lot to review here. It's Valgrind clean, though that's not difficult to achieve.
Certainly consider closing stream 3, unless you want to keep a means to emit unprefixed stderr messages.
One shortcoming is that the shell won't wait for sed to finish when it terminates. If the last process's output is still being filtered at this point, then you may fail to capture it - I observed this (repeatably) when running the program in Emacs compilation-mode.
One way you can improve on this if you're using GNU sed is by passing -u ("unbuffered") flag to sed. If you don't have GNU sed but do have GNU coreutils, then the stdbuf utility could make sed line-buffered for you:
stdbuf -oL -iL sed 's/^/ERROR: /'
With any sed, we could (and should) close stderr when we terminate and wait for sed to finish to be sure of catching all error output.
#!/bin/bash
exec 3>&2
exec 2> >(sed -u 's/^/ERROR: /' >&3)
exec 3>&-
# shellcheck disable=SC2064
trap "exec 2>&-; wait $!" EXIT
echo stdout
echo stderr >&2
$! after the exec. In order to flush the output of the child process, it is sufficient to close the input fd, which is fd 2 of the parent. After that one can wait for the child pid.
\$\endgroup\$
&1 where I meant &-. Sorry!
\$\endgroup\$