Skip to main content

How to Iterate with Counter in Bash

• 1 min read
bash loops iteration

Quick Answer: How to Create a Counter Loop

Use a C-style for loop: for ((i=0; i<10; i++)); do echo $i; done. This counts from 0 to 9, incrementing the counter each iteration.

Quick Comparison: Loop Methods

MethodBest ForSpeedReadability
C-style forFixed rangeFastExcellent
while loopConditional iterationFastGood
for…inArray iterationFastExcellent
seq (legacy)Generating sequencesMediumFair

Bottom line: Use C-style for loops for counting. Use for...in for arrays. Use while when you need conditional checks.


Why Use Counter Loops?

Counter loops are fundamental to programming. They let you run code a specific number of times, process ranges of numbers, or iterate through arrays by index. Whether processing files, retrying operations, or generating sequences, counter loops are essential.

The C-style for loop is the most common and readable approach for counter-based iteration.

The C-style for loop is the most common and readable approach. It works just like in C, Java, or Python.

for ((i=0; i<10; i++)); do
  echo "Count: $i"
done

Output:

Count: 0
Count: 1
Count: 2
...
Count: 9

The syntax breaks down as:

  • ((i=0)) - Initialize counter to 0
  • i<10 - Continue while condition is true (counter less than 10)
  • i++ - Increment counter after each iteration

This is the most readable and efficient counter loop syntax in Bash.

Common variations:

# Count from 1 to 10 (inclusive)
for ((i=1; i<=10; i++)); do
  echo $i
done

# Count by steps of 2
for ((i=0; i<10; i+=2)); do
  echo $i  # Prints: 0, 2, 4, 6, 8
done

# Countdown
for ((i=5; i>0; i--)); do
  echo "$i..."
done
echo "Blastoff!"

# Count a specific number of times
for ((i=1; i<=3; i++)); do
  echo "Run #$i"
done

When to Use Counter Loops

Use C-style for loops when:

  • You need to run code a specific number of times
  • Counting from A to B is the core logic
  • You need the index/counter value inside the loop
  • Performance matters (it’s very fast)

Use while loops when:

  • The exit condition is complex or data-dependent
  • You need to update multiple variables per iteration
  • Clarity is more important than brevity

Quick Reference

# Count from 0 to 9
for ((i=0; i<10; i++)); do echo $i; done

# Count from 1 to 10 (inclusive)
for ((i=1; i<=10; i++)); do echo $i; done

# Count by 2 (0, 2, 4, 6, 8)
for ((i=0; i<10; i+=2)); do echo $i; done

# Countdown from 5
for ((i=5; i>0; i--)); do echo "$i..."; done

# Using counter with arrays
array=(a b c d e)
for ((i=0; i<${#array[@]}; i++)); do
  echo "${array[$i]}"
done

Practical Example: Retrying Failed Commands

Here’s a real example where counter loops are crucial:

#!/bin/bash

# Retry a command up to 5 times
MAX_ATTEMPTS=5
ATTEMPT=0
SUCCESS=0

while (( ATTEMPT < MAX_ATTEMPTS )); do
  ((ATTEMPT++))
  echo "Attempt $ATTEMPT of $MAX_ATTEMPTS..."

  # Try to download a file
  if wget -q https://example.com/data.zip; then
    echo "Download successful!"
    SUCCESS=1
    break  # Exit loop on success
  else
    echo "Download failed. Waiting before retry..."
    sleep 2
  fi
done

if (( SUCCESS == 0 )); then
  echo "ERROR: Failed after $MAX_ATTEMPTS attempts"
  exit 1
fi

While Loop with Counter

The while loop approach is more verbose but sometimes clearer:

i=0
while (( i < 5 )); do
  echo "Iteration $i"
  ((i++))
done

# Output:
# Iteration 0
# Iteration 1
# Iteration 2
# Iteration 3
# Iteration 4

Processing Arrays with Counter Loops

Counter loops are perfect for accessing array elements by index:

#!/bin/bash

files=("file1.txt" "file2.txt" "file3.txt")

# Process each file
for ((i=0; i<${#files[@]}; i++)); do
  echo "Processing: ${files[$i]}"
done

# Output:
# Processing: file1.txt
# Processing: file2.txt
# Processing: file3.txt

Nested Counters

Sometimes you need loops within loops:

#!/bin/bash

# Create a multiplication table
for ((i=1; i<=5; i++)); do
  for ((j=1; j<=5; j++)); do
    result=$((i * j))
    printf "%2d " $result
  done
  echo  # Newline after each row
done

Output:

 1  2  3  4  5
 2  4  6  8 10
 3  6  9 12 15
 4  8 12 16 20
 5 10 15 20 25

Another nested example - processing multiple directories:

#!/bin/bash

# Process files in multiple directories
dirs=("/tmp" "/home" "/var")

for ((d=0; d<${#dirs[@]}; d++)); do
  dir="${dirs[$d]}"
  echo "Directory: $dir"

  for ((f=1; f<=3; f++)); do
    echo "  File $f"
  done
done

Break and Continue in Counter Loops

You can exit or skip iterations:

#!/bin/bash

# Break: exit loop early
for ((i=0; i<10; i++)); do
  if (( i == 5 )); then
    echo "Stopping at $i"
    break
  fi
  echo "Count: $i"
done

# Continue: skip to next iteration
for ((i=0; i<5; i++)); do
  if (( i == 2 )); then
    echo "Skipping $i"
    continue
  fi
  echo "Count: $i"
done

Real-World Example: Batch Processing

#!/bin/bash

# Process log files in batches
LOG_DIR="/var/log"
BATCH_SIZE=10
COUNT=0

for ((i=1; i<=100; i++)); do
  filename="$LOG_DIR/app_$(printf "%04d" $i).log"

  # Process file
  echo "Processing: $filename"

  ((COUNT++))

  # Every BATCH_SIZE files, do cleanup
  if (( COUNT % BATCH_SIZE == 0 )); then
    echo "Processed $COUNT files, running maintenance..."
    # Do cleanup or progress reporting
  fi
done

echo "Total processed: $COUNT files"

Performance Comparison: For Loop vs C-Style

#!/bin/bash

# C-style for loop (fast, recommended)
time for ((i=0; i<1000; i++)); do
  : # Do nothing
done

# While loop (also fast)
time {
  i=0
  while (( i < 1000 )); do
    : # Do nothing
    ((i++))
  done
}

# For-in loop (slower for large ranges - spawns subshell for each iteration)
time for i in {1..1000}; do
  : # Do nothing
done

Important Notes

  • Always use (( )) for arithmetic - it’s cleaner and more efficient
  • Initialize your counter before the loop
  • Don’t forget to increment/decrement the counter
  • Use meaningful variable names: for ((attempt=0; attempt<5; attempt++)) is clearer than for ((i=0; i<5; i++))
  • C-style for loops are the fastest; avoid for i in {1..1000} for large ranges

Quick Reference

# Count from 0 to 9
for ((i=0; i<10; i++)); do echo $i; done

# Count from 1 to 10
for ((i=1; i<=10; i++)); do echo $i; done

# Count by 5s
for ((i=0; i<50; i+=5)); do echo $i; done

# Countdown
for ((i=10; i>0; i--)); do echo $i; done

# While with counter
i=0
while (( i < 10 )); do
  echo $i
  ((i++))
done

Summary

Counter loops are one of the most fundamental patterns in shell scripting. The C-style for loop for ((i=0; i<N; i++)) is typically the clearest and most efficient choice. Master this pattern and you’ll be able to automate repetitive tasks effectively.