6

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
  • 197,895
  • 55
  • 485
  • 740
Saad
  • 101
  • 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) – pLumo Dec 08 '21 at 15:56
  • 1
    Sidenote: there's more than one way to increment a variable in Bash. 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

10

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
  • 88,010
  • 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
6

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
  • 46,324
  • 5
  • 88
  • 152