Shell Increment a shell variable

For SH(1) 'sh -- command interpreter (shell)' , which is better/simpler/clearer/efficient?

inc=0

1.
inc=$((${inc}+1))

2.
: $((inc+=1))

3.
$((inc+=1)) 2>/dev/null >&2
 
Option 3 is conceptually wrong, it tries to execute the expansion of the arithmetic expression as a command. Just don't do that. Assuming you have an executable file 6 somewhere in your PATH (as nonsensical as this would be, it's perfectly possible!), trying to increment 5 with your third method will also execute 6 as a side effect.

For the other two, I'd say you shouldn't waste any thought about "efficiency" comparing these. They both work without (expensive) calls to external tools, so it very much depends on the implementation of the shell.

As for clarity, I'd prefer the second option using the null-command, it's IMHO more readable.
 
[…] which is better/simpler/clearer/efficient?
Welcome to the FreeBSD forums. 👋 It depends. What are you doing? Incrementing is hardly an exercise by itself. 🧪 If it is not guaranteed that you stay within the 32‑bit range (the minimum range required to be supported by a POSIX‑compliant shell), you want to trigger some error.​
Bash:
x=$(getconf LONG_MAX)
printf '%s\n' $((x + 1))
This (possibly) prints a negative number, i. e. a wrong result 🪣, whereas​
Bash:
x=$(getconf LONG_MAX)
expr "${x:?Error: x is undefined.}" '+' '1'
(possibly) fails with an overflow error message. 🐟
 
Option 3 is conceptually wrong, it tries to execute the expansion of the arithmetic expression as a command. Just don't do that. Assuming you have an executable file 6 somewhere in your PATH (as nonsensical as this would be, it's perfectly possible!), trying to increment 5 with your third method will also execute 6 as a side effect.

For the other two, I'd say you shouldn't waste any thought about "efficiency" comparing these. They both work without (expensive) calls to external tools, so it very much depends on the implementation of the shell.

As for clarity, I'd prefer the second option using the null-command, it's IMHO more readable.
Regarding your comment for option 3 I ran:
mik@h14t:~ # inc=5
+ inc=5
mik@h14t:~ # $((inc+=1))
+ 6
-sh: 6: not found
So, yes, it is not the right thing to do.

I prefer option 2 but wanted to check my understanding that it 'does nothing' with the substituted result(6 in the example above).
 
Welcome to the FreeBSD forums. 👋 It depends. What are you doing? Incrementing is hardly an exercise by itself. 🧪 If it is not guaranteed that you stay within the 32‑bit range (the minimum range required to be supported by a POSIX‑compliant shell), you want to trigger some error.​
Bash:
x=$(getconf LONG_MAX)
printf '%s\n' $((x + 1))
This (possibly) prints a negative number, i. e. a wrong result 🪣, whereas​
Bash:
x=$(getconf LONG_MAX)
expr "${x:?Error: x is undefined.}" '+' '1'
(possibly) fails with an overflow error message. 🐟
Thanks for the welcome.
Yes 'Incrementing is hardly an exercise by itself' but I need to increment small counters, work flow status, return code etc in lots of different places.
I don't need large number capability for this and was interested to see if others could point out faults with option 2.
So my question was very simple and standalone.

mik@h14t:~ # x=$(getconf LONG_MAX)
+ getconf LONG_MAX
+ x=9223372036854775807 <= That's a big number! AFAICT for my purpose I need <=256.

mik@h14t:~ # printf '%s\n' $((x + 1))
+ printf '%s\n' -9223372036854775808
-9223372036854775808 <= Yes, negative.

mik@h14t:~ # expr "${x:?Error: x is undefined.}" '+' '1'
+ expr 9223372036854775807 + 1
expr: overflow <= Yes, overflow.
 
I don't need large number capability for this and was interested to see if others could point out faults with option 2.
With the caveats above (if you are dealing with large numbers / wrap / 32bit systems), yes, option 2 is a perfectly reasonable choice, and preferable to 1 (less for the shell to process).
 
I prefer option 2 but wanted to check my understanding that it 'does nothing' with the substituted result(6 in the example above).

Option 2 uses the "null command", which is guaranteed by POSIX to do nothing:
Actually, I'd say this is also the idiomatic way to do it if you really just need to increment your variable, without executing any command. That's exactly the purpose of :, to allow evaluations/expansions where a command would be expected, without causing any side effects. Of course, only use it if needed, e.g. something like:

Bash:
i=0
while [ $i -lt 10 ]; do
        : $((i += 1))
        echo $i
done

would be pretty stupid, just write echo $((i += 1)) instead.

Regarding the warnings about guaranteed range: They're absolutely valid, so keep them in mind. I just want to add: As long as you know for sure the 32bit range will always suffice, stick to the shell's arithmetics. expr typically isn't a shell builtin, so using it always means forking a new process.
 
Back
Top