How to Iterate with Counter in Bash
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
| Method | Best For | Speed | Readability |
|---|---|---|---|
| C-style for | Fixed range | Fast | Excellent |
| while loop | Conditional iteration | Fast | Good |
| for…in | Array iteration | Fast | Excellent |
| seq (legacy) | Generating sequences | Medium | Fair |
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.
C-Style For Loop (Recommended)
The C-style for loop is the most common and readable approach for counter-based iteration.
C-Style For Loop (Recommended)
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 0i<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 thanfor ((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.