How to Increment and Decrement a Variable in Bash: Counter Examples

By 

•

Updated on

•

7 min read

Incrementing and decrementing a counter variable in a Bash script

One of the most common arithmetic operations when writing Bash scripts is incrementing and decrementing variables. This is most often used in loops as a counter, but it can occur elsewhere in the script as well.

Incrementing and decrementing means adding or subtracting a value (usually 1), respectively, from the value of a numeric variable. The arithmetic runs inside double parentheses, either as the ((...)) command or the $((...)) expansion, or with the let built-in command.

This guide explains the most common ways to increment and decrement a variable in Bash.

Using the + and - Operators

The simplest way to increment or decrement a variable is by using the + and - operators.

sh
i=$((i+1))
((i=i+1))
let "i=i+1"
sh
i=$((i-1))
((i=i-1))
let "i=i-1"

This method allows you to increment or decrement the variable by any value you want.

Here is an example of incrementing a counter variable within an until loop:

sh
i=0

until [ $i -gt 3 ]
do
  echo i: $i
  ((i=i+1))
done
output
i: 0
i: 1
i: 2
i: 3

The += and -= Operators

In addition to the basic operators explained above, Bash also provides the assignment operators += and -=. These operators are used to increment or decrement the value of the left operand by the value specified after the operator.

sh
((i+=1))
let "i+=1"
sh
((i-=1))
let "i-=1"

In the following while loop, we are decrementing the value of the i variable by 5.

sh
i=20

while [ $i -ge 5 ]
do
  echo Number: $i
  let "i-=5"
done
output
Number: 20
Number: 15
Number: 10
Number: 5

Integer Variables with declare -i

Bash treats variables as strings unless you tell it otherwise, and that catches people out with +=. Outside an arithmetic context, += appends text instead of adding:

sh
i=5
i+=3
echo "i: $i"
output
i: 53

Bash joined 5 and 3 into 53. Declaring the variable as an integer with declare -i changes the rule for every later assignment to that variable, which makes += add and lets a bare i=i+1 work without the double parentheses:

sh
declare -i i=5
i+=3
echo "i: $i"
i=i+1
echo "i: $i"
output
i: 8
i: 9

The integer attribute stays with the variable, so use it when a variable holds nothing but counts. For a one-off increment, the ((...)) forms are clearer to a reader than a declare line further up the script.

Using the ++ and -- Operators

The ++ and -- operators increment and decrement, respectively, their operand by 1 and return the value.

sh
((i++))
((++i))
let "i++"
let "++i"
sh
((i--))
((--i))
let "i--"
let "--i"

The operators can be used before or after the operand. They are also known as:

  • prefix increment: ++i
  • prefix decrement: --i
  • postfix increment: i++
  • postfix decrement: i--

The prefix operators first increment or decrement the operand by 1 and then return the new value of the operand. The postfix operators return the operand’s value before it has been incremented or decremented.

If you only want to increment or decrement the variable and do not inspect the command’s exit status, both forms change the variable in the same way. Their exit statuses can differ, however, because an arithmetic command returns status 1 when its expression evaluates to 0. For example, ((i++)) returns status 1 when i starts at 0, while ((++i)) returns status 0.

This difference matters in scripts that use set -e, where standalone ((i++)) can stop the script on the first increment. Use i=$((i+1)) when you need an increment command that does not inherit the arithmetic result as its exit status.

The following examples demonstrate how the ++ operator works when used before and after its operand:

sh
x=5
y=$((x++))
echo x: $x
echo y: $y
output
x: 6
y: 5
sh
x=5
y=$((++x))
echo x: $x
echo y: $y
output
x: 6
y: 6

Below is an example of how to use the postfix increment operator in a Bash script:

~/counter.shsh
#!/bin/bash
i=0
while true; do
  if [[ "$i" -gt 3 ]]; then
    break
  fi
  echo "i: $i"
  ((i++))
done

The same operators drive the header of a C-style for loop , where the third part runs after every iteration and can step by any value:

sh
for ((i = 0; i < 6; i += 2)); do
  echo "i: $i"
done
output
i: 0
i: 2
i: 4

The loop stops at 6 without printing it, because the test runs before the body and 6 < 6 is false.

The disadvantage of using ++ and -- is that the variable can only be incremented or decremented by 1. For stepping by a larger value, use += or -= instead.

Quick Reference

MethodIncrementDecrement
Basic operatorsi=$((i+1))i=$((i-1))
Arithmetic context((i=i+1))((i=i-1))
let built-inlet "i=i+1"let "i=i-1"
Assignment operators((i+=1))((i-=1))
let assignmentlet "i+=1"let "i-=1"
Postfix shorthand((i++))((i--))
Prefix shorthand((++i))((--i))

For a printable quick reference, see the bash cheatsheet .

Troubleshooting

integer expression expected error
This usually means the variable is empty or contains non-numeric text. Initialize counters before arithmetic operations, for example i=0.

i++ fails with command not found
Use increment and decrement operators only in arithmetic contexts such as ((i++)) or $((i+1)). Writing i++ as a standalone command is not valid shell syntax.

Script works in Bash but fails in sh
Some arithmetic forms are Bash-specific. If the script uses Bash features like (( )), run it with Bash (#!/bin/bash) instead of sh.

Counter stays at 0 after a loop
By default, piping data into a loop runs the loop body in a subshell , so the increment lands on a copy of the variable and disappears when the loop exits:

sh
count=0
printf '%s\n' one two three | while read -r line; do
  ((count++))
done
echo "count: $count"
output
count: 0

Use process substitution to feed the loop through input redirection instead, and the counter survives:

sh
count=0
while read -r line; do
  ((count++))
done < <(printf '%s\n' one two three)
echo "count: $count"
output
count: 3

value too great for base error
A counter taken from a file, a timestamp, or command output can arrive with a leading zero, and Bash reads a leading zero as an octal number . 08 and 09 are not valid octal, so the increment fails. Force base 10 with the 10# prefix:

sh
i=08
i=$((10#$i+1))
echo "i: $i"
output
i: 9

FAQ

What is the difference between prefix and postfix increment?
Both change the variable by 1, but they differ when the result is used in an expression. y=$((x++)) assigns the original value to y, then increments x. y=$((++x)) increments x first, then assigns the new value to y. Their exit statuses can also differ when they are used as arithmetic commands, which matters with set -e or other status-based control flow.

Can I increment by a value other than 1?
Yes. Use ((i+=5)) or let "i+=5" to increment by any value. The ++ and -- shorthand only step by 1.

Where are counters most commonly used?
Counters are most often used inside for , while , and until loops to track iterations or build a step-based sequence.

Can I decrement below zero?
Yes. Bash arithmetic treats variables as signed integers, so a counter can go negative without any special handling.

Conclusion

Bash provides basic arithmetic, compound assignment, and prefix or postfix shorthand for changing counter variables. Use += or -= for larger steps, watch the exit status of ((i++)) in scripts that use set -e, and see our guide on how to run a Bash script for the next step.

Tags

Linuxize Weekly Newsletter

A quick weekly roundup of new tutorials, news, and tips.

About the authors

Dejan Panovski

Dejan Panovski

Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 1000+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.

View author page