0

This caught me by surprise: applying the post-increment operator (++) to a zero value variable results in a non-zero result code. That is, given:

#!/bin/bash
myvar=0
let myvar++
echo "result: $?"

Running that (with bash 5.1.0) results in:

result: 1

Why does that produce a nonzero result code? We see the same behavior using a numeric expression:

#!/bin/bash
myvar=0
(( myvar++ ))
echo "result: $?"

On the other hand, if we use += instead of ++, or if we start with a nonzero value of myvar, we receive a 0 result code as expected. The following...

myvar=1
let myvar+=1
echo "result: $?"

myvar=1
let myvar++
echo "result: $?"

myvar=1
(( myvar++ ))
echo "result: $?"

...all produce:

result: 0

What's going on here?

larsks
  • 277,717
  • 41
  • 399
  • 399

2 Answers2

1

From the bash man page, in the section describing let:

Each arg is an arithmetic expression to be evaluated (see ARITHMETIC EVALUATION). If the last arg evaluates to 0, let returns 1; 0 is returned otherwise

It's not the operator that establishes the value of $?, it is let. Since the value of the argument to let in the command let myvar++ is 0, let returns 1.

larsks
  • 277,717
  • 41
  • 399
  • 399
William Pursell
  • 204,365
  • 48
  • 270
  • 300
  • Spot on with the documentation; thanks! That sentence remains unclear to me. In `myvar=0; let myvar++`, I would say that the last arg evaluates to `1`. I would expect `$? == 1` after, say, `myvar=1; let myvar--`. – larsks Jun 02 '21 at 03:50
  • The operator is called **post**increment, not **pre**increment. You get as a result the value **before** incrementation. Hence, `x=1; echo $((1 + x++))` returns 2, not 3. – user1934428 Jun 02 '21 at 06:59
  • 1
    If `myvar` is set to 0, then @larsks `myvar++` evaluates to 0, while `++myvar` evaluates to 1. Both change `myvar` so that its new value is 1. – William Pursell Jun 02 '21 at 11:16
1

For post-increment expressions, bash evaluates the variable and sets the result code before applying the increment. In each case where the value before the post-increment was 0, it follows the documented behavior,

If the last arg evaluates to 0, let returns 1; 0 is returned otherwise.

Note the difference if you use pre-increment,

myvar=0
let ++myvar
echo "result: $?"

>> result: 0

In exp0() in https://git.savannah.gnu.org/cgit/bash.git/tree/expr.c#n1014 , for PREINC it binds the (stringifed) value of v2 then assigns it to val, but under POSTINC it binds the variable then discards v2 without assigning it to val.

chepner
  • 497,756
  • 71
  • 530
  • 681
jamieguinan
  • 1,640
  • 1
  • 10
  • 14