How to increment a variable in bash?

93

Solution 1

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.

Solution 2

var=$((var + 1))

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

Solution 3

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.

Solution 4

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.

Solution 5

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

Share:
93

Related videos on Youtube

Author by

Patrick Hellebrand

Updated on September 18, 2022

Comments

  • Patrick Hellebrand 3 months

    I have this script in jQuery, it scrolls to wanted section but with spacing to the top. It works fine on all tested browsers ... except firefox.

    $('nav > *').click(function(event){
        event.preventDefault();
        var navClicked = $(this).index();
        var elem = $(this).attr("href");
        $('body').scrollTop($(elem).offset().top - 48);
    });
    

    https://jsfiddle.net/5L3xyuuv/1/

    • frnt
      frnt over 6 years
      add your html codes too or create a jsfiddle.
    • Patrick Hellebrand over 6 years
    • vsync
      vsync over 6 years
      what kind of a test page is that? it's almost empty and doesn't reproduce the problem
    • vsync
      vsync over 6 years
      why did you do all this javascript anyway if it simply "jumps" to the id location on the page like a regular hash link does?
    • Patrick Hellebrand over 6 years
      because your 'jump' ignores the header height if theres one
  • gniourf_gniourf
    gniourf_gniourf about 9 years
    or ((++var)) or ((var=var+1)) or ((var+=1)).
  • Javier López
    Javier López about 9 years
    or var=$(expr $var + 1)
  • phunehehe
    phunehehe over 8 years
    Curiously, var=0; ((var++)) returns an error code while var=0; ((var++)); ((var++)) does not. Any idea why?
  • phunehehe
    phunehehe over 8 years
    @RaduRădeanu I'm sure, the same thing happens in zsh too. Actually maybe I didn't make myself clear. This prints 1 (an error code) instead of 0 (successful): var=0; ((var++)); echo $?.
  • Radu Rădeanu
    Radu Rădeanu over 8 years
    @phunehehe Look at help '(('. The last line says: Returns 1 if EXPRESSION evaluates to 0; returns 0 otherwise.
  • DreadPirateShawn
    DreadPirateShawn over 8 years
    I suspect the evaluation of zero as 1 is why @gniourf_gniourf's tip includes ((++var)) but not ((var++)).
  • rubo77
    rubo77 about 7 years
    So which is the most compatible way?
  • ArtOfWarfare
    ArtOfWarfare over 6 years
    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.
  • Patrick Hellebrand over 6 years
    your snippet works fine, but if ill copy it to my snippet, it stops working
  • Patrick Hellebrand over 6 years
    Could it be, that other jquery scripts cause this, but only on firefox?
  • frnt
    frnt over 6 years
    Then you need to go through your codes, as per your query this works perfectly fine on all browser.
  • MatthewRock
    MatthewRock almost 6 years
    Apparently speed correlates with command length. I wonder whether the commands call the same functions.
  • wjandrea
    wjandrea over 5 years
    is it safe to use let var++, without the quotes?
  • wjandrea
    wjandrea over 5 years
    You can also use i=$((i+1))
  • Radon Rosborough
    Radon Rosborough over 5 years
    If process substitution $(...) is available on this shell, I'd recommend using it instead.
  • Daniel Eisenreich
    Daniel Eisenreich about 5 years
    ((val++)) doesn't worked in my case. But if I use ((++val)) this worked. Some suggestions why?
  • arielf
    arielf over 4 years
    @DanielEisenreich both forms seem to work fine in bash version 4.3.48. Maybe you have an old version? $ val=0; echo $val; ((val++)); echo $val gives me: 0 1 `
  • Laurence Renshaw
    Laurence Renshaw over 4 years
    let only needs quotes if you put spaces in your expression
  • x-yuri
    x-yuri about 4 years
    @arielf You don't observe the behavior since most likely you don't set -e.
  • Sandeep about 4 years
    I'm surprised that $((var+1)) works. I would have expected $(($var+1)).
  • x-yuri
    x-yuri almost 4 years
    To make (( var++ )) work (not fail when var == 0) with set -e, do : $(( var++ )).
  • raygozag
    raygozag about 3 years
    Not what the OP asked.
  • Keith Reynolds
    Keith Reynolds about 3 years
    @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.
  • raygozag
    raygozag about 3 years
    It was already answered, the OP did not ask for performance evaluations, no matter how helpful you want to be, they didn't ask for it.
  • Jon Spencer
    Jon Spencer almost 3 years
    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.
  • sastorsl
    sastorsl over 2 years
    @JonSpencer you might be hitting this? unix.stackexchange.com/questions/402750/…
  • Timo
    Timo about 2 years
    Use a mix of let and arithmetic expanison and you are good to go.
  • Sephethus
    Sephethus about 2 years
    Why do absolutely none of these options anywhere work for me? I'm getting things like i++: not found or ++i not found or let not found or any number of errors. WTF?
  • Satoshi Nakamoto
    Satoshi Nakamoto 10 months
    Just to rememeber: ++var is prefix and var++ is postfix, there is a difference.