771

I have tried to increment a numeric variable using both var=$var+1 and var=($var+1) without success. The variable is a number, though bash appears to be reading it as a string.

Bash version 4.2.45(1)-release (x86_64-pc-linux-gnu) on Ubuntu 13.10.

0

9 Answers 9

1166

There is more than one way to increment a variable in bash, but what you tried will not work.

You can use, for example, arithmetic expansion:

var=$((var+1))
((var=var+1))
((var+=1))
((var++))

Or you can use let:

let "var=var+1"
let "var+=1"
let "var++"

See also: https://tldp.org/LDP/abs/html/dblparens.html.

17
  • 45
    or ((++var)) or ((var=var+1)) or ((var+=1)). Dec 3, 2013 at 18:30
  • 12
    Curiously, var=0; ((var++)) returns an error code while var=0; ((var++)); ((var++)) does not. Any idea why?
    – phunehehe
    Mar 26, 2014 at 9:36
  • 20
    @phunehehe Look at help '(('. The last line says: Returns 1 if EXPRESSION evaluates to 0; returns 0 otherwise. Mar 27, 2014 at 11:41
  • 5
    I suspect the evaluation of zero as 1 is why @gniourf_gniourf's tip includes ((++var)) but not ((var++)). Apr 23, 2014 at 16:17
  • 4
    is it safe to use let var++, without the quotes?
    – wjandrea
    Jun 14, 2017 at 20:20
216
var=$((var + 1))

Arithmetic in bash uses $((...)) syntax.

1
  • 19
    Vastly better than the accepted answer. In just 10% as much space, you managed to provide enough examples (one is plenty - nine is overkill to the point when you're just showing off), and you provided us with enough info to know that ((...)) is the key to using arithmetic in bash. I didn't realize that just looking at the accepted answer - I thought there was a weird set of rules about order of operations or something leading to all of the parenthesis in the accepted answer. Jun 22, 2016 at 13:56
116

Various options to increment by 1, and performance analysis

Thanks to Radu Rădeanu's answer that provides the following ways to increment a variable in bash:

var=$((var+1))
((var=var+1))
((var+=1))
((var++))
let "var=var+1"
let "var+=1" 
let "var++"

There are other ways too. For example, look in the other answers on this question.

let var++
var=$((var++))
((++var))
{
    declare -i var
    var=var+1
    var+=1
}
{
    i=0
    i=$(expr $i + 1)
}

Having so many options leads to these two questions:

  1. Is there a performance difference between them?
  2. If so which, which performs best?

Incremental performance test code:

#!/bin/bash

# To focus exclusively on the performance of each type of increment
# statement, we should exclude bash performing while loops from the
# performance measure. So, let's time individual scripts that
# increment $i in their own unique way.

# Declare i as an integer for tests 12 and 13.
echo > t12 'declare -i i; i=i+1'
echo > t13 'declare -i i; i+=1'
# Set i for test 14.
echo > t14 'i=0; i=$(expr $i + 1)'

x=100000
while ((x--)); do
    echo >> t0 'i=$((i+1))'
    echo >> t1 'i=$((i++))'
    echo >> t2 '((i=i+1))'
    echo >> t3 '((i+=1))'
    echo >> t4 '((i++))'
    echo >> t5 '((++i))'
    echo >> t6 'let "i=i+1"'
    echo >> t7 'let "i+=1"'
    echo >> t8 'let "i++"'
    echo >> t9 'let i=i+1'
    echo >> t10 'let i+=1'
    echo >> t11 'let i++'
    echo >> t12 'i=i+1'
    echo >> t13 'i+=1'
    echo >> t14 'i=$(expr $i + 1)'
done

for script in t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14; do
    line1="$(head -1 "$script")"
    printf "%-24s" "$line1"
    { time bash "$script"; } |& grep user
    # Since stderr is being piped to grep above, this will confirm
    # there are no errors from running the command:
    eval "$line1"
    rm "$script"
done

Results:

i=$((i+1))              user    0m0.992s
i=$((i++))              user    0m0.964s
((i=i+1))               user    0m0.760s
((i+=1))                user    0m0.700s
((i++))                 user    0m0.644s
((++i))                 user    0m0.556s
let "i=i+1"             user    0m1.116s
let "i+=1"              user    0m1.100s
let "i++"               user    0m1.008s
let i=i+1               user    0m0.952s
let i+=1                user    0m1.040s
let i++                 user    0m0.820s
declare -i i; i=i+1     user    0m0.528s
declare -i i; i+=1      user    0m0.492s
i=0; i=$(expr $i + 1)   user    0m5.464s

Conclusion:

It seems bash is fastest at performing i+=1 when $i is declared as an integer. let statements seem particularly slow, and expr is by far the slowest because it is not a built into bash.

6
  • Apparently speed correlates with command length. I wonder whether the commands call the same functions. Jan 5, 2017 at 15:40
  • Not what the OP asked.
    – raygozag
    Dec 15, 2019 at 18:12
  • 6
    @raygozag The op asked how to increment. My answer first list many methods. How does that not directly answer the op question? Then it provide time information for each method. All that is, is just extra information to assist the op in choosing which method he wants to use. Dec 15, 2019 at 18:33
  • 1
    I found that on Bash 3.2.57, using declare -i x and then doing x+=1 in a loop (doing other thing), x did not increment more than one time. The let and (()) methods worked fine. Jan 9, 2020 at 21:59
  • 1
    @JonSpencer you might be hitting this? unix.stackexchange.com/questions/402750/…
    – sastorsl
    May 27, 2020 at 10:25
23

There's also this:

var=`expr $var + 1`

Take careful note of the spaces and also ` is not '

While Radu's answers, and the comments, are exhaustive and very helpful, they are bash-specific. I know you did specifically ask about bash, but I thought I'd pipe in since I found this question when I was looking to do the same thing using sh in busybox under uCLinux. This portable beyond bash.

2
  • 1
    You can also use i=$((i+1))
    – wjandrea
    Jun 14, 2017 at 22:58
  • If process substitution $(...) is available on this shell, I'd recommend using it instead. Aug 24, 2017 at 18:54
11

If you declare $var as an integer, then what you tried the first time will actually work:

$ declare -i var=5
$ echo $var
5
$ var=$var+1
$ echo $var
6

Reference: Types of variables, Bash Guide for Beginners

9

There's one method missing in all the answers - bc

$ VAR=7    
$ bc <<< "$VAR+2"
9
$ echo $VAR
7
$ VAR=$( bc <<< "$VAR+1" )
$ echo $VAR
8

bc is specified by POSIX standard, so should be present on all versions of Ubuntu and POSIX-compliant systems. The <<< redirection could be altered to echo "$VAR" | bc for portability, but since the question asks about bash - it's OK to just use <<<.

6

The return code 1 issue is present for all default variants (let, (()), etc.). This often causes trouble, e.g., in scripts that use set -o errexit. Here is what I am using to prevent error code 1 from math expressions that evaluate to 0;

math() { (( "$@" )) || true; }

math a = 10, b = 10
math a++, b+=2
math c = a + b
math mod = c % 20
echo $a $b $c $mod
#11 12 23 3
1

This has to be the worst way to accomplish such a simple task but I just wanted to document it for fun I guess (complete opposite of code golf).

$ var=0
$ echo $var
0
$ var="$(python -c 'print('$var'+1)')"
$ echo $var
1

or

$ var="$(printf '%s\n' $var'+1' | bc)"
$ echo $var
1

Seriously use one of the other much better choices here.

0

This is the safe bet

(( var = var + 1 ))

If the resulting value is non zero, then setting exit on error will stop Your script

set -e
var=0
(( var++ ))
echo You will never get here

Not the answer you're looking for? Browse other questions tagged or ask your own question.