Re: Bug when trapping exit from subshell

2014-05-19 Thread Chet Ramey
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

2014-05-19 Thread Mark Ferrell
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

2014-05-19 Thread Greg Wooledge
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

2014-05-19 Thread Mark Ferrell
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;"