[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: bash 3.2.51, ERR traps and subshells
From: |
Stefano Lattarini |
Subject: |
Re: bash 3.2.51, ERR traps and subshells |
Date: |
Tue, 22 Jun 2010 11:15:55 +0200 |
User-agent: |
KMail/1.12.1 (Linux/2.6.30-2-686; KDE/4.3.4; i686; ; ) |
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