I see that many questions have been asked and answered on SE about redirections in Bash using exec, but none seem to answer my question.
What I'm trying to accomplish is redirect all output to stderr in a script to a temporary fd and restitute it back to stderr only in case of non-successful script termination. The ability to restore the contents of stderr is needed in case of a non-successful termination, for returning to the caller information about the error. Redirecting stderr to /dev/null
would discard both irrelevant noise and useful information. As much as possible, explicit temporary files should be avoided, as they add a number of other issues (see https://dev.to/philgibbs/avoiding-temporary-files-in-shell-scripts). The contents of stdout should be returned transparently to the caller. It will be ignored by the caller in case of non-successful termination of the script, but the script shouldn't need to care about that.
The reason for doing this is that the script is called from another program that considers any output to stderr an error, instead of testing for a non-zero exit code. In the example below, openssl echoes a progress indicator to stderr which does not indicate an error and can be ignored upon successful completion of the command.
Below is a simplified version of my script (note that openssl here is only a placeholder for arbitrary and possibly more complex instructions):
#!/bin/bash
set -euo pipefail
# Redirect stderr to temp fd 3
exec 3>&2
# In case of error, copy contents of fd 3 to stderr
trap 'cat <&3 >&2' ERR
# Upon exit, restore original stderr and close fd 3
trap 'exec 2>&3 3>&-' EXIT
# This nonetheless outputs the progress indicator to stderr
openssl genpkey -algorithm RSA
But I'm obviously missing something as the script keeps printing out the content of stderr upon successful termination, but now blocks upon failure. I guess I'm confused with how redirections with exec work. What am I getting wrong?
/dev/null
or to a file? Doing either would prevent the script from producing any output on that stream, at least not when running the command that you have redirected./dev/nul
would discard both the progress indicator and useful information. As much as possible I'm also trying to avoid explicit temp files, which add a number of other issues (see dev.to/philgibbs/avoiding-temporary-files-in-shell-scripts).exec 3>&2
makes the descriptor number3
point to the same open file description as2
, but it does not prevent programs from using their inherited2
. (2) "Restore the contents" cannot be done without some kind of buffer (a temporary file may be such buffer) and supporting code. I don't think simple redirections can do this.cat <&3
after writing to it, you need to reopen the descriptor 3, then the pointer (seek) will be located at the beginning and not at the end of a stream.