set -e is not clearly documented
Hi, lets consider the following: $ echo $BASH_VERSION 4.1.2(1)-release $ cat /etc/system-release Red Hat Enterprise Linux Server release 6.3 (Santiago) $ ( set -e; echo foo; false; echo bar; ) # this one is expected foo $ ( set -e; echo foo; false; echo bar; ) || true # this one is not expected foo bar documentation (http://www.gnu.org/software/bash/manual/bash.html) states that: [...] The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test in an if statement, part of any command executed in a && or || [...] In this case it is not clear since set -e is invoked inside subshell and || is outside this subshell. What I would expect to happen is ( set -e; echo foo; false; echo bar; ) || exit $? to exit with exit code of a last failed command in a subshell.
Re: Command substitution and exiting from deeply nested subshells
On Sun, Oct 06, 2013 at 09:37:00PM -0300, Carlos Pita wrote: > I'm not completely sure whether this is a bug or not but it seems > not possible to immediately exit a shell when an error happens at 2+ > levels of subshell nesting. Exiting in a subshell will never cause the parent shell to exit, regardless of depth. imadev:~$ (exit 1); echo I did not exit I did not exit If you want a child process (which includes subshells) to be able to tell the parent process to terminate, then you must arrange some interprocess communication channel to send that information. This could be as simple as "if I return -1, you should exit", or it could be something more complicated involving signals, or a file, or a named pipe. > I've tested this with set -e, set -E, an ERR trap, All of those are useless and should be avoided. If handling errors is important to you, then you should handle them. Yourself. See http://mywiki.wooledge.org/BashFAQ/105 for details. Bash is required to IMPLEMENT set -e because it's in the POSIX specification. You are not required to USE it.
Re: set -e is not clearly documented
On Mon, Oct 07, 2013 at 11:01:11AM +0200, Bart?omiej Palmowski wrote: > $ ( set -e; echo foo; false; echo bar; ) # this one is expected > foo > $ ( set -e; echo foo; false; echo bar; ) || true # this one is not expected > foo > bar set -e is useless rubbish that should be avoided. See http://mywiki.wooledge.org/BashFAQ/105 for details. Bash is required to IMPLEMENT set -e because it's part of the POSIX specification. You are not required to USE it.
Re: Command substitution and exiting from deeply nested subshells
On 10/6/13 8:37 PM, Carlos Pita wrote: > I'm not completely sure whether this is a bug or not but it seems > not possible to immediately exit a shell when an error happens at 2+ > levels of subshell nesting. Specifically, there is a command at the > top-level shell waiting for the results of a command substitution. > This second command in the first subshell is in turn waiting for the > results of another command substitution. This innermost command fails > but the awaiting commands still finish their execution as if the error > never happened. I've tested this with set -e, set -E, an ERR trap, > explicit exits at each subshell, but to no avail. Below is an example > to reproduce it. > > Repeat-By: > > trap 'exit 1' ERR > > set -e -E > > function xxx { > echo xxx1 > exit 1 > echo xxx2 > } > > function yyy { > echo $(xxx) yyy > } > > yyy > > # => xxx1 yyy > # I wouldn't expect the echo to print any output or execute at all. $(xxx) is a word expansion, not a command. Bash will only pay attention to the exit status of command substitution in one case (x=$(foo)). This command substitution doesn't contribute to any other command's exit status, especially `echo', and `set -e' doesn't cause the shell to pay attention to it. 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: set -e is not clearly documented
On 10/7/13 5:01 AM, Bartłomiej Palmowski wrote: > Hi, > > lets consider the following: > > $ echo $BASH_VERSION > 4.1.2(1)-release > $ cat /etc/system-release > Red Hat Enterprise Linux Server release 6.3 (Santiago) > $ ( set -e; echo foo; false; echo bar; ) # this one is expected > foo > $ ( set -e; echo foo; false; echo bar; ) || true # this one is not expected > foo > bar > > documentation (http://www.gnu.org/software/bash/manual/bash.html) states > that: > > [...] The shell does not exit if the command that fails is part of the > command list immediately following a while or until keyword, part of the > test in an if statement, part of any command executed in a && or || [...] > > In this case it is not clear since set -e is invoked inside subshell and || > is outside this subshell. The subshell command is clearly part of the || compound command. The subshell `knows' that it is part of || and set -e has no effect. This example has been discussed before, on this list and the austin-group Posix list, and the bash behavior is correct. 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: Command substitution and exiting from deeply nested subshells
> $(xxx) is a word expansion, not a command. Bash will only pay attention to > the exit status of command substitution in one case (x=$(foo)). This > command substitution doesn't contribute to any other command's exit status, > especially `echo', and `set -e' doesn't cause the shell to pay attention > to it. Thanks Chet, it's clear now. > Exiting in a subshell will never cause the parent shell to exit, > regardless of depth. This is not true in general. set -e; (exit 1); echo "I don't exist" >> I've tested this with set -e, set -E, an ERR trap, > All of those are useless and should be avoided. Ok, I'm not particularly interested in using them, I was just reinforcing my point. Best regards -- Carlos
Re: Command substitution and exiting from deeply nested subshells
On Mon, Oct 07, 2013 at 11:58:48AM -0300, Carlos Pita wrote: > > Exiting in a subshell will never cause the parent shell to exit, > > regardless of depth. > > This is not true in general. > set -e; (exit 1); echo "I don't exist" In this case, it is the "set -e" which may or may not cause the parent shell to terminate, depending on which shell you're doing this in. imadev:~$ bash-4.3 -c 'set -e; (exit 1); echo "I do not exist"' imadev:~$ bash-4.2 -c 'set -e; (exit 1); echo "I do not exist"' imadev:~$ bash-4.1 -c 'set -e; (exit 1); echo "I do not exist"' imadev:~$ bash-4.0 -c 'set -e; (exit 1); echo "I do not exist"' imadev:~$ bash-3.2 -c 'set -e; (exit 1); echo "I do not exist"' I do not exist The exit itself is *not* propagated upward, and please see my previous comments about the reliability and usefulness of set -e (i.e. none).