For Loops

Do something 100 times. Process every file in a directory. Iterate over a list. That's what for loops do.

Basic For Loop

hljs bash
#!/bin/bash

for name in Alice Bob Charlie; do
    echo "Hello, $name!"
done
Terminal
$./greet.sh
Hello, Alice! Hello, Bob! Hello, Charlie!

Loop Over Files

hljs bash
#!/bin/bash

for file in *.txt; do
    echo "Processing: $file"
done
Terminal
$./process.sh
Processing: file1.txt Processing: file2.txt Processing: notes.txt

No Matches?

If no .txt files exist, *.txt doesn't expand and the loop runs once with literal *.txt. Check for this:

hljs bash
for file in *.txt; do
    [[ -f "$file" ]] || continue
    echo "$file"
done

Loop Over Command Output

hljs bash
#!/bin/bash

for user in $(cat /etc/passwd | cut -d: -f1); do
    echo "User: $user"
done

Or better:

hljs bash
#!/bin/bash

for dir in $(ls /var/log); do
    echo "Log directory: $dir"
done

Range of Numbers

hljs bash
#!/bin/bash

# Using brace expansion
for i in {1..5}; do
    echo "Number: $i"
done
Terminal
$./count.sh
Number: 1 Number: 2 Number: 3 Number: 4 Number: 5

With Step

hljs bash
# Count by 2s
for i in {0..10..2}; do
    echo "$i"
done
# Output: 0 2 4 6 8 10

# Count backwards
for i in {5..1}; do
    echo "$i"
done
# Output: 5 4 3 2 1

C-Style For Loop

hljs bash
#!/bin/bash

for (( i=0; i<5; i++ )); do
    echo "Index: $i"
done
Terminal
$./index.sh
Index: 0 Index: 1 Index: 2 Index: 3 Index: 4

Useful when you need:

  • Custom start/end
  • Custom increment
  • Access to the counter

Loop Control

Skip Iteration: continue

hljs bash
#!/bin/bash

for i in {1..5}; do
    if [[ $i -eq 3 ]]; then
        continue  # skip 3
    fi
    echo "$i"
done
# Output: 1 2 4 5

Exit Loop: break

hljs bash
#!/bin/bash

for file in *.log; do
    if [[ "$file" == "error.log" ]]; then
        echo "Found error.log, stopping"
        break
    fi
done

Practical Examples

Batch Rename Files

hljs bash
#!/bin/bash
# Add prefix to all .txt files

for file in *.txt; do
    mv "$file" "backup_$file"
done

Process Multiple Servers

hljs bash
#!/bin/bash

servers="web1 web2 web3 db1"

for server in $servers; do
    echo "Checking $server..."
    ping -c 1 "$server" > /dev/null && echo "  UP" || echo "  DOWN"
done

Create Multiple Directories

hljs bash
#!/bin/bash

for month in {01..12}; do
    mkdir -p "reports/2025/$month"
done

Backup Multiple Databases

hljs bash
#!/bin/bash

databases="users products orders"

for db in $databases; do
    echo "Backing up $db..."
    mysqldump "$db" > "${db}_backup.sql"
done
Knowledge Check

What does {1..5..2} expand to?

Quick Reference

SyntaxPurpose
for x in a b cLoop over list
for f in *.txtLoop over files
for i in {1..10}Loop over range
for i in {0..10..2}Range with step
for ((i=0;i<n;i++))C-style loop
continueSkip to next iteration
breakExit loop early

Key Takeaways

  • for var in list; do ... done is the basic structure
  • Glob patterns like *.txt iterate over matching files
  • {1..10} creates number ranges
  • {1..10..2} adds a step
  • C-style loops (( )) for complex counters
  • continue skips, break exits
  • Always quote "$var" in loops

Next: while loops for conditional repetition.