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?

Asked By: Naik

||

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 "%.3dn" $((++BN)) > Build.number
Answered By: Stephen Kitt

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 +.

Answered By: Stéphane Chazelas

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} ))
Answered By: mosvy

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
Answered By: Kaz