Bash exit status of shorthand increment notation
Asked Answered
H

2

15

I noticed an apparent inconsistency in the return status of bash's (( )) notation.
Consider the following

$> A=0
$> ((A=A+1))
$> echo $? $A
0 1

However using the other well known shorthand increment notation yields:

$> A=0
$> ((A++))
$> echo $? $A
1 1

If one has the builtin set -e in the script the second notation will cause the script to exit, since the exit status of the ((A++)) returned non-zero. This question was more or less addressed in this related question. But it does not seem to explain the difference in exit status for the two notations ((A=A+1)) and ((A++))

((A++)) seems to return 1 if and only if A equals 0. (Disclaimer: I have not done exhaustive tests. Tested in bash 4.1.2 and 4.2.25). So the final question boils down to:

Why does A=0; ((A++)) return 1?

Housemother answered 15/3, 2014 at 19:49 Comment(0)
R
9

a++ is post-increment: it increments after the statement is evaluated. By contrast, ++a increments before. Thus:

$ a=0 ; ((a++)) ; echo $a $?
1 1
$ a=0 ; ((++a)) ; echo $a $?
1 0

In the first case, ((a++)), the arithmetic expression is evaluated first, while a is still zero, yielding a value of zero (and hence a nonzero return status). Then, afterward, a is incremented.

In second case, ((++a)), a is incremented to 1 and then ((...)) is evaluated. Since a is nonzero when the arithmetic expression is evaluated, the return status is zero.

From man bash:

   id++ id--
          variable post-increment and post-decrement
   ++id --id
          variable pre-increment and pre-decrement
Roxanaroxane answered 15/3, 2014 at 19:55 Comment(4)
It seems so obvious now, thanks. However this seems to imply that whenever one uses set -e, it is impossible to use either shorthand notation safely for a counter, if the counter is expected to potentially take the value of -1 or 0. Is there a way around this? Or should one simply abandon the shorthand notationHousemother
@Pankrates, a great many of the folks in #bash suggest abandoning the use of set -e. See mywiki.wooledge.org/BashFAQ/105. That said, you can also run (( a++ )) ||:Pentadactyl
@Charles very useful link, thank you. However the conclusion of the article is still undecided. On the one hand "Do not use it, use your own error checking" versus "Use it but beware of gotcha's", as demonstrated in my original question. I would prefer to use set -e (convenience I guess) but only if there is an exhaustive list of said gotcha's. Since I don't have one (if there even exists such a list), I think I will go with your advice :)Housemother
Yes -- I said "a great many", not "all", as the consensus is split -- I'm actually on the "use it if familiar with the caveats" side. OTOH, Greg -- the primary maintainer of the wiki hosting that FAQ -- is on the "best-avoided" end of the debate.Pentadactyl
P
3

The exit status of the (()) notation is zero if the arithmetic expression is nonzero, and vice versa.

A=A+1

You assign 1 to A, so the expression evaluates to 1, exit status zero.

A++

POST-increment operator. The expression evaluates to zero, exit status 1, and then A is incremented.

Package answered 15/3, 2014 at 19:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.