5

Incrementing a variable var works in bash when enclosed in double parentheses like (( var++ )). But I have found that it fails if variable is set to 0 beforehand like var=0.

$ a=0
$ ((a++)) && echo "command succeeded" || echo "command failed"
command failed

$ a=1
$ ((a++)) && echo "command succeeded" || echo "command failed"
command succeeded

Can someone explain this behavior?

Environment:

I am using gnome-terminal on Ubuntu Desktop 18.04.5 LTS.

muru
  • 193,181
  • 53
  • 473
  • 722
Saad
  • 91
  • 6
  • 4
    I think you should not really on the exit status of `((` to know if the command was working.. *>> "If the result of the expression is 0, the exit status code returned will be 1 or “false”, while the exit status code returned by a non-zero value expression will be 0 or “true”."* ([via](https://developpaper.com/functions-of-in-linux-shell-2)) – pLumo Dec 08 '21 at 15:56
  • 1
    Sidenote: there's more than one way to [increment a variable in Bash](/q/385528/301745). Probably the most idiomatic is to explicitly make it an integer first: `declare -i a=0` then `a+=1`. – wjandrea Dec 09 '21 at 00:16
  • @pLumo, it's not the exit status that's wrong, but the users' assumptions (yours, too). It works exactly like post-increment is defined, and exactly like it does in e.g. C. Though you're right in that you can't use the exit status of `(( .. ))` to see if it _worked_, since a syntax error also makes it exit with status 1. (and not e.g. 2, like `[` and `[[` do) – ilkkachu Dec 09 '21 at 10:05
  • @pLumo, exit status code is of concern to me because script is using `trap ... ERR` and this line provokes it. I have avoided this scenario, for now, by using pre-increment as my base value is 0 for `var`. But this solution is specific to my use case. Maybe I should search for a way to bypass `trap` for such/selected statements. – Saad Dec 11 '21 at 07:48

2 Answers2

9

With credit from here: https://unix.stackexchange.com/questions/146773/why-bash-increment-n-0n-return-error

The return value of (( expression )) does not indicate an error status, but, from the bash manpage:

((expression)) The expression is evaluated according to the rules described below under ARITHMETIC EVALUATION. If the value of the expression is non-zero, the return status is 0; otherwise the return status is 1. This is exactly equivalent to let "expression".

In ((a++))you are doing a post increment. The value of a is 0 so 1 is returned, after that, it is incremented.

Compare

$ unset a
$ ((a++)) ; echo Exitcode: $? a: $a
Exitcode: 1 a: 1

versus

$ unset a
$ ((++a)) ; echo Exitcode: $? a: $a
Exitcode: 0 a: 1

A pre-increment, so a has become 1 and 0 is returned.

vanadium
  • 82,909
  • 6
  • 116
  • 186
  • Technically, the increment occurs before the return; however, the returned value is the value taken before the increment. – wizzwizz4 Dec 09 '21 at 18:06
5

This works for me (in bash in Ubuntu),

$ a=0
$ echo $((a++))
0
$ echo $((a++))
1
$ echo $((a++))
2
$ echo $((a++))
3
$ echo $a
4

Notice the difference with

$ a=0
$ echo $((++a))
1
$ echo $((++a))
2
$ echo $((++a))
3
$ echo $a
3
sudodus
  • 45,126
  • 5
  • 87
  • 151