Re: Bug when trapping exit from subshell
On 5/18/14, 12:56 PM, Mark Ferrell wrote: > I believe that if you actually execute the script as intended you will > find that your reading of the code is incorrect. Really though, > redirection should not be the problem since: > > 1. Redirection of the output of one command does not change the > redirection of the script as a whole, and so it should never change > redirection of the command invoked by the handler. Changing > redirection of the script as a whole via 'exec' sure .. but not for a > single command. It depends on the context in which the exit trap is executed. The `set -e' causes the shell to exit as soon as a command fails, and the exit trap is run while the shell is exiting, in the context of the failed command. In this case, that's `main', which has its stdout and stderr redirected. If you remove the set -e, you get different behavior. The exit_handler function is always called: if you add something like `touch exit_handler' you'll see that that file is always created. It's not a question of whether or not the trap is executed, it's a question of whether or not bash unwinds the redirections on its way out of the shell. When bash executes a builtin or shell function in a subshell, or bails because a command is not found, it doesn't bother to do that. Chet -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: Bug when trapping exit from subshell
I stand corrected. After adding a 'touch' to the script, it does indeed appear to be calling the exit handler. So it the redirection of the output to the error handler only happens if a builtin/function failed (error on an external command does not result in a redirection), and this behaviour is only only in observed in bash. I'm sorry, but the lack of consistency still sounds like it is a bug in bash. The behaviour I would expect is functionally equivalent to 'do_cmd > /dev/null 2>&1 || err_handler'. Further more, this IS the behaviour seen if the command being executed is NOT a builtin/function. The following scripts demonstrate functionally equivalent code which has different output behaviour due to the error_handler() being redirected. Please note that these scripts are expected to have the SAME output, and they simply do not when interpreted by bash (though, as repeatedly mentioned, they do have the same output when interpreted by ash, dash, BusyBox's ash, ksh and zsh). # Apparently builtins have a secret-subshell during 'set -e' resulting in # behavior which mimcs: ( builtin_false || err_handler ) > /dev/null 2>&1 set -e exit_handler() { echo "exit code: $?"; } false() { /bin/false; } main() {( trap exit_handler 0 false >> /dev/null 2>&1 )} main "$@" # External commands (and builtin/functions in other shells) handle this # use case as: /bin/false > /dev/null 2>&1 || err_handler set -e exit_handler() { echo "exit code: $?"; } main() {( trap exit_handler 0 /bin/false >> /dev/null 2>&1 )} main "$@" On Mon, May 19, 2014 at 7:00 AM, Chet Ramey wrote: > On 5/18/14, 12:56 PM, Mark Ferrell wrote: >> I believe that if you actually execute the script as intended you will >> find that your reading of the code is incorrect. Really though, >> redirection should not be the problem since: >> >> 1. Redirection of the output of one command does not change the >> redirection of the script as a whole, and so it should never change >> redirection of the command invoked by the handler. Changing >> redirection of the script as a whole via 'exec' sure .. but not for a >> single command. > > It depends on the context in which the exit trap is executed. The `set -e' > causes the shell to exit as soon as a command fails, and the exit trap is > run while the shell is exiting, in the context of the failed command. In > this case, that's `main', which has its stdout and stderr redirected. If > you remove the set -e, you get different behavior. > > The exit_handler function is always called: if you add something like > `touch exit_handler' you'll see that that file is always created. It's > not a question of whether or not the trap is executed, it's a question > of whether or not bash unwinds the redirections on its way out of the > shell. When bash executes a builtin or shell function in a subshell, or > bails because a command is not found, it doesn't bother to do that. > > Chet > > -- > ``The lyf so short, the craft so long to lerne.'' - Chaucer > ``Ars longa, vita brevis'' - Hippocrates > Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: Bug when trapping exit from subshell
On Mon, May 19, 2014 at 10:39:59AM -0700, Mark Ferrell wrote: > I'm sorry, but the lack of consistency still sounds like it is a bug > in bash. The behaviour I would expect is functionally equivalent to > 'do_cmd > /dev/null 2>&1 || err_handler'. Further more, this IS the > behaviour seen if the command being executed is NOT a > builtin/function. I won't take sides on that particular issue, but as a workaround, could you use something like this? exec 8>&1 9>&2 # Save original stdout & stderr for use in error handler err() { echo "${1:-Error}" >&9; }
Fwd: Bug when trapping exit from subshell
On Mon, May 19, 2014 at 10:45 AM, Greg Wooledge wrote: > On Mon, May 19, 2014 at 10:39:59AM -0700, Mark Ferrell wrote: >> I'm sorry, but the lack of consistency still sounds like it is a bug >> in bash. The behaviour I would expect is functionally equivalent to >> 'do_cmd > /dev/null 2>&1 || err_handler'. Further more, this IS the >> behaviour seen if the command being executed is NOT a >> builtin/function. > > I won't take sides on that particular issue, but as a workaround, could > you use something like this? > > exec 8>&1 9>&2 # Save original stdout & stderr for use in error handler > err() { echo "${1:-Error}" >&9; } Yah, I may have to do something along those lines to get around this for backwards compatibility with what can only be deemed as a bash bug. POSIX states the following in regards to trap: "The environment in which the shell executes a trap on EXIT shall be identical to the environment immediately AFTER the last command executed before the trap on EXIT was taken." I think this is pretty clear. error_handler() should not have its output redirected as it should be handled as if "following" the command which triggered the exit. "cmd > /dev/null 2>&1 ; error_handler;"