bug-bash
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]