Why isn't Bash trap working if output is redirected to stdout?

The other answer advises exec &> /dev/tty, so traps write to /dev/tty regardless of previous redirections:

The traps are run, but the standard output redirect to /dev/null is still in place, so the output is not printed. […] add exec &> /dev/tty to work around it by re-establishing the connection from standard output/error to the terminal.

Sometimes this may not be the best solution. Consider a general case when you want your script ("fixed" with exec &> /dev/tty) to be silent. You invoke

./the_script >/dev/null 2>/dev/null

but then the trap is triggered and it writes to /dev/tty anyway.

For me a better way is to store the original stdout and stderr in a form of "backup" file descriptors:

# at the very beginning of the script
exec 21>&1
exec 22>&2

Then, inside the trap function, you either redirect any single command:

echo "Some output" >&21
echo "Some error" >&22

or restore the original destinations and proceed as usual:

# at the beginning of the trap function
exec 1>&21
exec 2>&22

This way the redirections applied to the interrupted command won't affect the trap; still the redirections applied to the entire script will.


The traps are run, but the standard output redirect to /dev/null is still in place, so the output is not printed. Try replacing the trap contents with touch "$FUNCNAME" to verify, or add exec &> /dev/tty to work around it by re-establishing the connection from standard output/error to the terminal. As to why, this may be part of a larger feature to keep a lot of the original environment when running traps in order to avoid surprises.