Bug when trapping exit from subshell

2014-05-16 Thread Mark Ferrell
The following script properly reports the exit code to the calling
environment, , but the exit handler is not called if a function
triggers the exit vs an external command.

Script executed via:
bash 

Re: Bug when trapping exit from subshell

2014-05-18 Thread Mark Ferrell
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.
  2. Redirection would not have effected the output when 2 different
commands where used for handling the exit condition.  As mentioned in
the first email, the exit handler gets called and reports properly
when the script is handed /bin/false as the command to execute.
  3. Again, as previously stated .. the output is valid when
interpreted  with dash, ksh, and zsh.  It is only when interpreted
with bash that it fails.
  4. Changing the body of main() from {( ... )} to { ... } results in
bash calling the exit handler.

The lack of space in '!:' in this context acts as an invalid command.
If you actually "run" the script and hand it various commands to test
against, say "true", "false", "/bin/false", or "no/such/command" you
will find that the exit handler DOES indeed get called for valid
commands, even if the command returns a non-zero exitcode.  So
/bin/false results in the exit handler being called, but the builtin
false() does not, nor will 'no/such/command'.

Lastly, this script was the simplest example I could come up with
after finding this bug, the original use-case had the exit handler
logging to a file in which the message was lost when interpreted by
bash.

On Fri, May 16, 2014 at 9:48 PM, Maarten Billemont  wrote:
> the exit handler is called, you just muted it.  remove the redirections, and
> you'll also notice you need a space after your !
>
>
> On 16 May 2014 12:41, Mark Ferrell  wrote:
>>
>> The following script properly reports the exit code to the calling
>> environment, , but the exit handler is not called if a function
>> triggers the exit vs an external command.
>>
>> Script executed via:
>> bash 

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/



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;"