Bash loops are one of those foundational tools you reach for constantly. Need to process files in bulk? Retry something with backoff? Rename 50 photos with sequential numbers? A solid loop is your best friend. Let’s cover the most practical patterns you’ll actually use, from simple ranges to stepping, zero-padding, and real-world scenarios.
The Classic Range Loop
Start simple. Count from 1 to 100:
for i in {1..100}; do echo $idoneThat brace expansion {1..100} is pure Bash and super efficient. Add a timestamp to each output:
for i in {1..100}; do echo "$(date +"%D %I:%M:%S") - $i"doneStepping Through a Range
Every 3rd number instead of every 1:
for i in {1..100..3}; do echo "$(date +"%D %I:%M:%S") - $i"doneThe third parameter is the step size. Want every 5th? Use {1..100..5}.
The seq Command
Before brace expansion, there was seq. It’s handy for dynamic ranges:
# Count from 1 to 100seq 1 100
# Every 2nd numberseq 1 2 100
# Backwardsseq 100 -1 1
# Zero-padded output (useful for filenames)seq -w 1 100With seq -w, you get 001, 002, 003...100 instead of 1, 2, 3...100. That’s huge for file sorting.
C-Style for Loops
If you need more control, go C-style:
for ((i=1; i<=100; i++)); do echo $idone
# Every 2nd numberfor ((i=1; i<=100; i+=2)); do echo $idone
# Countdown from 100 to 1for ((i=100; i>=1; i--)); do echo $idoneThis syntax is familiar to anyone who’s touched C, Java, or JavaScript. Use it when you need conditional increments or complex logic.
While Loops with Counters
A while loop with a manual counter gives you maximum flexibility:
i=1while [ $i -le 100 ]; do echo $i ((i++))doneOr countdown:
i=10while [ $i -gt 0 ]; do echo "Retry in $i seconds..." sleep 1 ((i--))doneecho "Go!"Real-World Example: Batch File Renaming with Counters
Say you have 50 JPG files from your camera and want to rename them sequentially:
#!/bin/bashcounter=1for file in *.jpg; do newname=$(printf "photo_%03d.jpg" $counter) mv "$file" "$newname" ((counter++))doneThe printf "photo_%03d.jpg" gives you photo_001.jpg, photo_002.jpg, etc. — padded with zeros so they sort correctly. Without zero-padding, photo_10.jpg comes before photo_2.jpg alphabetically. Gross.
Practical Example: Retry Loop with Countdown
Deploying something flaky? Retry with a countdown between attempts:
#!/bin/bashmax_attempts=5attempt=1
while [ $attempt -le $max_attempts ]; do if curl -s https://api.example.com/health > /dev/null; then echo "Health check passed!" exit 0 fi
if [ $attempt -lt $max_attempts ]; then countdown=5 while [ $countdown -gt 0 ]; do echo "Attempt $attempt failed. Retrying in $countdown seconds..." sleep 1 ((countdown--)) done fi
((attempt++))done
echo "All $max_attempts attempts failed."exit 1Looping Over Arrays with Counting
Sometimes you need both the index and the value:
fruits=("apple" "banana" "cherry" "date")
# Old school: C-style loopfor ((i=0; i<${#fruits[@]}; i++)); do echo "$i: ${fruits[$i]}"done
# Newer bash: loop with index trackingi=0for fruit in "${fruits[@]}"; do echo "$i: $fruit" ((i++))doneOutput: 0: apple, 1: banana, etc.
Progress Percentage Counter
Calculating progress for a long-running loop:
#!/bin/bashtotal=100
for ((i=1; i<=total; i++)); do # Do work here sleep 0.1
# Calculate percentage percent=$((i * 100 / total)) printf "\rProgress: %d%%" $percentdone
echo ""echo "Done!"The \r carriage return overwrites the same line, giving you a nice progress ticker without spamming your terminal.
Key Takeaways
- Brace expansion
{1..100}is fast and clean for simple ranges - seq shines when you need zero-padding or dynamic ranges
- C-style loops are familiar and flexible for complex logic
- While loops excel when you need granular counter control
- Zero-padding with
seq -worprintf "%03d"prevents file sorting disasters - Nested loops (loop + countdown) handle retry/backoff patterns beautifully
Pick the right tool for your use case. A simple range loop doesn’t need C-style syntax. But for retries, progress tracking, or countdown logic? That’s where while loops and C-style loops earn their keep. Your future self maintaining this script will appreciate clarity over cleverness.