At Tuesday 22 June 2010, Andres P wrote: > Bash 4.1 does not set the ERR trap: > > $ env -i HOME="$HOME" TERM="$TERM" bash3 <<\! > > set -o errexit > set -o errtrace > > TRIGGERED_ERR() { return $?; } > > trap 'TRIGGERED_ERR' ERR > > set -o xtrace > > var=$(false) || true Here, the subshell has (correctly) no way to know that there is a `||' after the command substitution, so it acts like a bare `false' command was used, and the ERR trap is correctly triggered *in the subshell*. > echo $? > > var=$(false || true) # only way of not triggering it... > echo $? > > ! > > ++ false # Subshell false > +++ TRIGGERED_ERR # Ignores outer "|| true" No, it doesen't even see it; the script seen by the subshell consists just of the string "false", so there is no `||' the subshell can see. And this seems IMHO quite natural if you remember that the parent shell and the subshell are run in two different proceses.
> +++ return 1 > + var= > + true > + echo 0 > 0 # But the entire command line does > # not set off errexit > ++ false > ++ true # Predictable second subshell... > + var= > + echo 0 > 0 > > > Before I write a patch, is this bug documented? I could not find it > in the archives. > > Is it a bug at all or is it expected behaviour? I think it's definitely expected behaviour. > According to the man page, it is not: > > The ERR trap is not executed if the failed command is part of the > command list immediately following a while or until keyword, > part of the test in an if statement, part of a && or ⎪⎪ list, But your `false' command is *not* part of such a list: it's part of a *command substitution* that is part of a variable assignement that is part of a `||' list. And is the failure returned by this assingnement that is being ignored thanks to the trailing `|| true'. In fact, if you leave that assingnement alone: var=$(false) you'll see that the ERR trap is executed by both the subshell (for the failed `false') and the parent shell (for the failed `var=$(false)'). For example: $ cat >foo.sh <<'END' set -o errtrace TRIGGERED_ERR() { echo $BASHPID, $? >&2; } trap 'TRIGGERED_ERR' ERR set -x echo parent: $BASHPID >&2 var=$(echo child: $BASHPID >&2; false) END $ bash foo.sh + echo parent: 20348 parent: 20348 ++ echo child: 20349 child: 20349 ++ false +++ TRIGGERED_ERR +++ echo 20349, 1 # this is the subshell 20349, 1 + var= ++ TRIGGERED_ERR ++ echo 20348, 1 # this is the parent shell 20348, 1 HTH, Stefano