Bash increment variable: add 1, counters, loops, and `(( ))` vs `$(( ))`

Bash increment variable and bash add 1 to variable with $(( )), ((++)), bash increment variable in loop (for/while), bash increment counter patterns, let, and post vs pre-increment pitfalls.

Published

Updated

Read time 4 min read

Reviewed byDeepak Prasad

Bash increment variable: add 1, counters, loops, and `(( ))` vs `$(( ))`

You bump a counter for every line processed, for every host in a list, or for every retry. In Bash that almost always means integer arithmetic in $(( … )) or (( … )), or a for (( … )) header that advances the index for you. The patterns below stay readable; pay extra attention to post- vs pre-increment when you reuse the expression’s value in another assignment.

Tested all the commands and code from this article on Ubuntu 25.04, kernel 6.14.0-37-generic, Bash 5.2.37.

For comparisons inside loops, keep bash compare numbers nearby.


Bash add 1 to variable (the usual patterns)

Plain arithmetic expansion: var=$((var + 1))

Works everywhere you need a new value; no side effects beyond assignment:

bash
x=5
x=$((x + 1))
echo "$x"

Output:

text
6

Arithmetic command: ((var++)) and ((++var))

(( … )) evaluates like the inside of a C expression. var++ returns the old value then increments; ++var increments then returns the new value.

Standalone (you only care about the final x):

bash
i=0
((i++))
echo "after post-increment alone: $i"

Output:

text
after post-increment alone: 1

When you capture the expression, the difference matters:

bash
i=0
j=$((i++))
echo "j=$j i=$i"

i=0
j=$((++i))
echo "j=$j i=$i"

Output:

text
j=0 i=1
j=1 i=1

Compound assignment inside (( ))

bash
x=5
((x += 2))
echo "$x"

Output:

text
7

let (older style, still valid)

bash
let x=1
let x+=2
echo "$x"

Output:

text
3

expr (external, POSIX—avoid for hot loops)

bash
y=1
y=$(expr "$y" + 1)
echo "$y"

Output:

text
2

Bash increment variable in loop

C-style for (( … ))

The third clause of for ((i=0; i<n; i++)) is the classic bash increment variable in loop form (see the full bash for loop write-up):

bash
for ((i = 0; i <= 3; i++)); do
  echo "i=$i"
done

Output:

text
i=0
i=1
i=2
i=3

Separate counter over a word list

When you iterate words but still need an index:

bash
n=0
for name in a b c; do
  echo "$n: $name"
  ((n++))
done
echo "final count: $n"

Output:

text
0: a
1: b
2: c
final count: 3

Bash increment counter with while

Same arithmetic; often paired with read or a condition (see bash while loop):

bash
count=0
while [[ $count -lt 3 ]]; do
  echo "count=$count"
  ((count++))
done

Output:

text
count=0
count=1
count=2

Integer-only arithmetic

(( … )) and $(( … )) treat variables as integers. Strings that are not valid integers cause errors—normalize input first or stay in string land.

Declare integers when it helps clarity (optional):

bash
declare -i hits=0
((hits++))
echo "$hits"

Output:

text
1

Pitfalls worth remembering

  • set -u: incrementing an unset variable is an error—initialize n=0 before ((n++)).
  • set -e: ((x++)) returns exit status 1 when the expression’s value is 0 (post-increment still “returns” the old value). Starting from x=0, a bare ((x++)) can therefore stop the script. Safer under set -e: ((++x)), ((x+=1)), or x=$((x+1)).
  • Post vs pre inside assignments ($((i++)) vs $((++i)))—easy to get off-by-one when you also use the return value.
  • Floating point: use bc or awk; ((x += 0.1)) is not the Bash integer model.

Quick reference (pick one style per script)

Style Example Typical use
Expansion assign x=$((x+1)) clearest “add n”
(( post ((x++)) bump inside loops
(( pre ((++x)) need new value in same expression
(( add n ((x+=5)) step sizes other than 1
let let x+=1 legacy scripts
expr x=$(expr "$x" + 1) portability without Bash

Summary

Incrementing in Bash is integer work: x=$((x+1)) is the clearest “add one,” ((x++)) or ((++x)) match C habits (watch post- vs pre-increment when you reuse the expression’s value), and the third clause of for ((…; …; i++)) is the usual loop counter form. while and until counters follow the same arithmetic rules. Stick to one style per script, initialize variables before set -u, and reserve expr for rare portability needs—(( )) keeps counter code short and fast.

Further reading:

Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …