Counter Increment and Decrement in Bash Loops

Written by: Linuxopsys   |   Last updated: August 21, 2023

1. Introduction

Counters play a crucial role in loop constructs in the Bash scripting language. Loop counters in Bash scripting are commonly employed to keep track of iterations or control the number of iterations a loop should execute.

In this guide, we will delve into the techniques of incrementing and decrementing counters within Bash loops.

2. Incrementing Counters in Bash Loops

Incrementing counters in Bash loops is a fundamental operation that often controls the behavior and execution of loops. The two primary methods for performing these operations in Bash are using arithmetic expansion (((...))) and the let command.

Arithmetic Approach:

One of the efficient ways to handle arithmetic operations, including incrementing counters, is using arithmetic expansion.

You can increment a counter using the ‘+’ operator or the ‘++’ operator. This method provides a straightforward way to adjust the counter value.

counter=$((counter + 1))
counter=$((counter++))
  • counter=$((counter + 1)) - This expression uses arithmetic expansion to increment the counter variable by 1.
  • counter=$((counter++)) - This expression uses the post-increment operation, which increases the value of counter by 1.

The ‘++’ operator comes in handy when we need to increment our counter by a value of one, but in some cases, we might need to change that value which is where the ‘+’ makes more sense.

Note: The ‘++’ operator can be used both before the variable (++counter) and after (counter++). The difference is that the pre-increment (++counter) applies the increment immediately, whereas the post-increment (counter++) change applies after the script goes to the next line.

Using let for increment:

The let command in Bash is used for arithmetic operations. It can be employed to increment (or decrement) counters within loops. It evaluates the arithmetic expression inside the double quotes.

let “counter = counter + 1”
let “counter++”

This command increments the value of the counter variable by 1. Both do the same.

2.1. Using arithmetic for Increment in a Loop

For Loop:

Syntax:

for ((counter=<initial_value>; counter<=<upper_limit>; counter++)); do

#code to execute on each iteration

done

If we want to increment by a value different than 1, then the syntax is as follows:

for ((counter=<initial_value>; counter<=<upper_limit>; counter+=<increment_value>)); do
	#code to execute on each iteration
done

Since loops with an increment value different than 1 are rarely used we will be showing an example with the ‘++’ operator. This script uses a for loop in Bash to iterate over a range of numbers.

#!/bin/bash
for ((counter=1; counter<=5; counter++)); do
	echo “Iteration: $counter”
done
increment counter in for loop using arithmetic method

Here initializes a counter at 1 and increments it by 1 in each iteration until it reaches 5. During each iteration, it prints "Iteration:" followed by the current value of the counter.

Until Loop:

#!/bin/bash
counter=1
until ((counter>5)); do
	echo “Iteration: $counter”
	((counter++))
done
increment counter in until loop using arithmetic method

The script initializes a counter at 1 and then uses an until loop to repeatedly print the iteration number, incrementing the counter after each iteration, until the counter exceeds 5.

2.2. Using let for Increment in a Loop

while loop:

Syntax:

counter=initial_value
while [ $counter -le upper_limit ]; do
#code to execute on each iteration
let “counter++”
done

We can see that in the arithmetic approach instead of using the ((...)) brackets we are using [...]. Apart from that there is no less than or equal ‘<=’ symbol.

Instead of -le operator, we use the following options based on your logic:

  • -lt (less than)
  • -le (less than or equal)
  • -gt (greater than)
  • -ge (greater than or equal)
  • -eq (equal)
  • -ne (not equal).

Example:  Here instead of incrementing our counter by using double brackets “((...))”, we use the let command.

#!/bin/bash
counter=1
while [ $counter -le 5 ]; do
	echo “Iteration: $counter”
	let “counter++”
done
increment counter in while loop using let command

It’s important to note that to achieve the same result as the for loop we need to put our increment as the last line in the while loop. However, if we do want to achieve different results we can move it around.

3. Decrementing Counters in Bash Loops

When it comes to decrementing counters they work in a similar way to incrementing counters. The main difference apart from changing our “++” operator to the “--” operator is that the initial value and upper limit values get swapped. Decrementing counters can be particularly useful when we want to go through an array in the reverse order, or to make a simple countdown as shown in the following examples.

Arithmetic Approach:

The arithmetic approach follows the same methodology except instead of increasing the value of our counter we are decreasing it.

counter=$((counter - 1))
counter=$((counter--))

The ‘--’ operator comes in handy when we need to decrement our counter by a value of one, but in some cases we might need to change that value which is where the ‘-’ makes more sense.

Using let command:

The let command follows the same methodology where we are only required to swap the ‘+’ character with the ‘-’ character

let “counter = counter - 1”
let “counter--”

3.1. Using arithmetic for decrement in a Loop

for loop:

Syntax:

for ((counter=<initial_value>; counter>=<lower_limit>; counter–)); do
	#code to execute on each iteration
done

If we want to decrement by a different value than 1 we can use the “-=” operator the following way:

for ((counter=<initial_value>; counter>=<lower_limit>; counter-=<increment_value>)); do
	#code to execute on each iteration
done

Example: Here we will be counting down from 5 to 1.

#!/bin/bash
for ((counter=5; counter>=1; counter--)); do
	echo “Iteration: $counter”
done
decrement counter in for loop using arithmetic method

Taking a look at the output we can see that our loop once again iterates 5 times, but this time in a decreasing order.

3.2. Using let for decrement in a Loop

while loop:

Syntax:

counter=initial_value
while [ $counter -ge lower_limit]; do
#code to execute on each iteration
let “counter--”
done

Example:

#!/bin/bash
counter=5
while [ $counter -ge 1 ]; do
	echo “Iteration: $counter”
	let “counter--”
done

The script starts with a counter set at 5 and uses a while loop to print the iteration number, decrementing the counter by 1 after each iteration, until the counter is less than 1.

Until Loop:

Example:

#!/bin/bash
counter=5
until ((counter<1)); do
	echo “Iteration: $counter”
	((counter--))
done

The script initializes a counter at 5 and then uses an until loop to print the iteration number, decrementing the counter after each iteration, until the counter falls below 1.

Subshell behavior

Let's try to count the number of lines in myfile.txt that contain the word "hello".

A naive approach might look like this:

#!/bin/bash

COUNTER=0
cat myfile.txt | grep 'hello' | while read LINE
do
    let COUNTER++
done

echo "Number of lines with 'hello': $COUNTER"

This script has a flaw due to the subshell behavior in bash. When using a pipe (|), the right side runs in a subshell. In this script, the while loop runs in a subshell because of the pipes, so the main shell's COUNTER variable isn't updated. This means that the script will always output 'Number of lines with 'hello': 0', regardless of how many times "hello" appears in the file.

To fix this, you can use process substitution:

#!/bin/bash

COUNTER=0
while read LINE
do
    let COUNTER++
done < <(grep 'hello' myfile.txt)

echo "Number of lines with 'hello': $COUNTER"
SHARE

Comments

Please add comments below to provide the author your ideas, appreciation and feedback.

Leave a Reply

Leave a Comment