Bash-4.1 expression behavior change under "set -e"

linux fan linuxscratch at
Tue Jun 22 06:49:54 PDT 2010

grep -C 1 "[[][[] and (("  bash-4.1/CHANGES

j.  The [[ and (( commands are now subject to the setting of `set -e' and the
    ERR trap.

c.  Changed the [[ and (( compound commands to set PIPESTATUS with their exit

When a script has the 'set -e' to exit on any non-zero exit status,
and the script has an expression such as '(( foo = bar ))'
whose purpose is to set the variable foo equal to the expression bar,
bash version 4.1.0 will exit when foo becomes equal to zero
as a result of setting foo equal to bar.

Earlier versions of bash would continue to process under 'set -e'
as if there had not been a non-zero exit status.

A small test program verified the different behavior vs. earlier versions:

# save as: fooey
# usage: sh fooey [-e]
[ "$1" == "-e" ] && set $1
while (( b > -10 ));do
  (( b = b - 1))
  echo "$? $b"

The imaginary intent of the above test program was to print the
decreasing numbers 9 through -10 preceeded by the exit code of setting
the value. The imaginary unexpected result was the abrupt exit before
printing the number zero.

I guess the behavior change was so that they could write in the bash man page:
((expression)) ...  is exactly equivalent to let "expression"

Replacing '(( b = b - 1))' with 'let b="$b - 1"' in the above performs
identically in bash version 4.1.0 whereas in previous versions there
was a variance.

To replicate the old behavior, we have been afforded the opportunity
to modify all code of that type so that it has an "or" branch which
does nothing thusly:
(( b = b - 1)) || :

An alternative is to use the thing called "Arithmetic Expansion" that
looks like $((expression)) and which does not trigger an exit when
expression becomes zero in the "set -e" situation:
b=$((b - 1))

My little mind's logical concept of setting a variable to zero
successfully is that it succeeded rather than failed.

One line of code which I noticed failing was this line in jhalfs' progress bar:
(( PREV_SEC = SEC ))
The impact was that the progress bar abruptly exited for no apparent reason.

Newer is better except always.


More information about the lfs-support mailing list