# How to increment the value of a (decimal) variable (with leading zero) by +1?

I have a file in the name of Build.number with the content value 012 which I need to increment by +1. So, I tried this

``````BN=\$(\$cat Build.number)
BN=\$((\$BN+1))
echo \$BN >Build.number
``````

but here I am getting the value 11 when I am expecting 013. Can anyone help me?

• There are two good answers, both not only explaining the cause of the problem, but providing additional information that might be useful. Stephen's provides a reference and Stéphane's mentions other shells and provides a more efficient way of reading the data without using the `cat` program. The ideal answer would combine both. (The ideal answer would also use `"%.3d\n"` format rather than the old leading 0 trick, which is ancient style, and misleading because in that case the leading 0 doesn't mean octal.) – Ray Butterworth Oct 9 '19 at 13:22
• – Jeff Schaller Oct 9 '19 at 13:48
• @Ray why is `.3d` better than `03d`? Apart from the octal confusion... – Stephen Kitt Oct 9 '19 at 14:13
• @StephenKitt. For d, i, o, u, x, X, a, A, e, E, f, F, g, and G conversion specifiers, leading zeros (following any indication of sign or base) are used to pad to the field width rather than performing space padding, except when converting an infinity or NaN. If the 0 and - flags both appear, the 0 flag is ignored. For d, i, o, u, x, and X conversion specifiers, if a precision is specified, the 0 flag shall be ignored. [CX] [Option Start] If the 0 and <apostrophe> flags both appear, the grouping characters are inserted before zero padding. For other conversions, the behavior is undefined. – Ray Butterworth Oct 9 '19 at 16:27
• @StephenKitt, the `.3d` makes the intent much more obvious: An optional precision that gives the minimum number of digits to appear for the d, i, o, u, x, and X conversion specifiers. The `03d` syntax dates back to the original 1970s version, and preserving backward compatibility has made its rules extremely complicated. – Ray Butterworth Oct 9 '19 at 16:28

The leading 0 causes Bash to interpret the value as an octal value; 012 octal is 10 decimal, so you get 11.

To force the use of decimal, add `10#` (as long as the number has no leading sign):

``````BN=10#\$(cat Build.number)
echo \$((++BN)) > Build.number
``````

To print the number using at least three digits, use `printf`:

``````printf "%.3d\n" \$((++BN)) > Build.number
``````
• It would be nice to have an answer that's not a bashism, since most people (need to) write `#!/bin/sh` scripts not bash scripts. – R.. GitHub STOP HELPING ICE Oct 12 '19 at 13:19
• @R.. have it here – mosvy Oct 13 '19 at 7:56
• @Stephen Kitt i am trying to run the following method in powershell. But its not taking up, getting bad arithmetic expression. is there any other method can be used for running in powershell – Naik Jan 6 '20 at 6:58
• @Naik the answer above was written for Bash, I don’t know the equivalent in PowerShell. – Stephen Kitt Jan 6 '20 at 8:01

`bash` treats constants that start with `0` as octal numbers in its arithmetic expressions, so `011` is actually `9`.

That's actually a POSIX requirement.

Some other shells like `mksh` or `zsh` ignore it (unless in POSIX compliant mode) as it gets in the way far more often than it is useful.

With `ksh93`, `BN=011; echo "\$((\$BN))"` outputs `9`, but `echo "\$((BN))"` outputs 11.

In `bash`, you can use `BN=\$((10#\$(<Build.number)))`, which should work as long as the number doesn't start with `-` or `+`.

In any POSIX shell, you can prevent a number from being considered octal by stripping its leading zeros with a combination of the `\${var#prefix}` and `\${var%%suffix}` expansion forms:

``````BN=001002; BN=\$(( \${BN#\${BN%%[!0]*}} + 1 )); echo "\$BN"
1003
``````

In shells which support the `\${var//pat/repl}` syntax, you can also do that by prepending it a `1` and subtracting it from `10^{number_of_digits}`:

``````BN=000012; BN=\$(( 1\$BN - 1\${BN//?/0} )); echo "\$BN"; BN=\$((BN+1)); echo "\$BN"
12
13
``````

This works in `bash`, `zsh`, `ksh93`, `mksh` and `yash`.

In `bash`, `ksh93` and `zsh` (but not in `yash` and `mksh`) you can also use the fortranish `**` operator (exponentiation):

``````BN=000012; BN=\$(( 1\$BN - 10**\${#BN} ))
``````
• For any shell, use: `BN=\$(( 1\$BN - 1\$(printf "%0*d\n" "\${#BN}" 0) ))` – ImHere Oct 11 '19 at 15:13

Here is a function to increment a numeric string. It observes leading zeros and tries to preserve the number of digits. It uses no variables, so it doesn't require any shell extension for declaring local variables, and doesn't pollute the variable namespace:

``````# \$1 -- decimal string, possibly with leading zeros or sign
# \$2 -- integer increment, no leading zeros.
incnumstr()
{
if [ \$1 -lt 0 ] ; then
set -- \$(incnumstr \${1#-} \$((- \$2)))
[ \$1 -le 0 ] && printf "%s" \${1#-}  \
|| printf "%s" -\$1
return
fi

set -- \${1#-} \$2 # strip leading minus from zero

[ \$1 -eq 0 ] && printf "%s%0.*d" "\$3" \${#1} \$2 \
|| printf "%s%0.*d" "\$3" \${#1} \$(( \${1#\${1%%[1-9]*}} + \$2 ))
}
``````

Interactive tests:

``````\$ echo \$(incnumstr 0 0)
0
\$ echo \$(incnumstr -0 0)
0
\$ echo \$(incnumstr 0 1)
1
\$ echo \$(incnumstr 0 -1)
-1
\$ echo \$(incnumstr 00 1)
01
\$ echo \$(incnumstr 00 -1)
-01
\$ echo \$(incnumstr -10 10)
00
\$ echo \$(incnumstr -10 11)
01
\$ echo \$(incnumstr -10 20)
10
\$ echo \$(incnumstr -10 99)
89
\$ echo \$(incnumstr -10 110)
100
\$ echo \$(incnumstr 100 -90)
010
\$ echo \$(incnumstr 100 -99)
001
\$ echo \$(incnumstr 100 -100)
000
\$ echo \$(incnumstr 100 -101)
-001
\$ echo \$(incnumstr 100 -1234)
-1134
\$ echo \$(incnumstr -0000 0)
0000
\$ echo \$(incnumstr -0000 1)
0001
\$ echo \$(incnumstr -0000 -2)
-0002
``````