|

Linux CLI 64 ๐Ÿง for loop in shell scripts

โฑ๏ธ Estimated read: 16 min | |

#!/bin/bash

for i in 1 2 3 4 5
do
    echo "Number: $i"
done

for i in $(seq 1 5)
do
    echo "Number: $i"
done

for (( i=1; i<=5; i++ ))
do
    echo "Number: $i"
done

for i in {1..5}
do
    echo "Number: $i"
done

for file in *.sh
do
    echo "Processing file: $file"
done

for i in {1..3}
do
    for j in {1..3}
    do
        echo "i: $i, j: $j"
    done
done

for file in $(ls)
do
    echo "File: $file"
done

The for loop is the most-used loop in shell scripting. Where while and until repeat until a condition changes, for iterates over a known list of items โ€” numbers, words, files, command output. It’s the loop you reach for when you know what you’re looping over.

Key point: Bash gives you five ways to write a for loop. They all repeat a block, but they differ in how the list is generated: literal items, seq, C-style arithmetic, brace expansion, or glob patterns. Pick the one that reads most naturally for the job.


a – for loop in shell scripts intro

A for loop is used to iterate over a sequence of items or values. This type of loop is very useful for executing the same command or set of commands multiple times with different inputs.

Basic syntax:

for variable in item1 item2 ... itemN
do
    # Commands to be executed for each iteration
done
  • variable is a placeholder that takes on each value from the item list, one at a time
  • items are values or items (like numbers, strings, file names) that the loop will iterate over

C-style syntax:

for (( initialization; condition; increment ))
do
    # Commands to be executed for each iteration
done
  • Initialization โ€” executed once before the loop starts. Usually initializes one or more variables.
  • Condition โ€” evaluated at the start of every iteration. If true (non-zero), the body runs; if false (zero), the loop ends.
  • Increment โ€” executed after each iteration, typically updating the loop variable(s).

The five forms of for:

FormExampleBest for
Literal listfor i in 1 2 3 4 5Small fixed lists
seqfor i in $(seq 1 5)Dynamic ranges
C-stylefor ((i=1; i<=5; i++))Numeric loops with logic
Brace expansionfor i in {1..5}Simple numeric ranges
Globfor file in *.shFile iteration

How the loop flows:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚           for loop flow                      โ”‚
โ”‚                                              โ”‚
โ”‚  for i in a b c                              โ”‚
โ”‚      โ”‚                                       โ”‚
โ”‚      โ–ผ                                       โ”‚
โ”‚  i = "a"  โ†’ run body                         โ”‚
โ”‚      โ”‚                                       โ”‚
โ”‚      โ–ผ                                       โ”‚
โ”‚  i = "b"  โ†’ run body                         โ”‚
โ”‚      โ”‚                                       โ”‚
โ”‚      โ–ผ                                       โ”‚
โ”‚  i = "c"  โ†’ run body                         โ”‚
โ”‚      โ”‚                                       โ”‚
โ”‚      โ–ผ                                       โ”‚
โ”‚  no more items โ†’ exit loop                   โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Break and continue work the same as in while:

for i in 1 2 3 4 5; do
    [ $i -eq 3 ] && break      # exits the loop at 3
    echo "$i"
done
for i in 1 2 3 4 5; do
    [ $i -eq 3 ] && continue   # skips 3
    echo "$i"
done

for vs while:

Aspectforwhile
Iterates overA known listWhile a condition is true
ConditionImplicit โ€” end of listExplicit โ€” you write it
Use forLists, files, rangesCounters, waiting, polling
Risk of infinite loopNo (unless list is infinite)Yes (if you forget to increment)

Common for loop uses:

  • Process every file matching a pattern
  • Run a command N times
  • Iterate over command-line arguments
  • Loop over an array
  • Generate numbered sequences
  • Nested iteration (pairs, grids, combinations)

b – for loop examples

Here are the seven examples from the top of the chapter, explained one by one.

1. Simple loop over a literal list:

for i in 1 2 3 4 5
do
    echo "Number: $i"
done
[ Number: 1 ]
[ Number: 2 ]
[ Number: 3 ]
[ Number: 4 ]
[ Number: 5 ]

The list is written explicitly. Each value is assigned to i in turn, and the body runs.

2. Simple loop using seq:

for i in $(seq 1 5)
do
    echo "Number: $i"
done
[ Number: 1 ]
[ Number: 2 ]
[ Number: 3 ]
[ Number: 4 ]
[ Number: 5 ]

seq 1 5 prints the numbers 1 through 5, and command substitution $(...) turns that output into a list of words. The loop iterates over each word.

seq is useful when the range is computed:

start=10
end=20
for i in $(seq "$start" "$end"); do
    echo "$i"
done

seq also supports a step:

$ seq 0 2 10
[ 0 ]
[ 2 ]
[ 4 ]
[ 6 ]
[ 8 ]
[ 10 ]

3. Simple loop using C-style syntax:

for (( i=1; i<=5; i++ ))
do
    echo "Number: $i"
done
[ Number: 1 ]
[ Number: 2 ]
[ Number: 3 ]
[ Number: 4 ]
[ Number: 5 ]

The C-style form is the most flexible for numeric loops. You control initialization, condition, and increment separately:

# Count down
for (( i=5; i>=1; i-- )); do
    echo "$i"
done

# Step by 2
for (( i=0; i<=10; i+=2 )); do
    echo "$i"
done

# Multiple variables
for (( i=0, j=10; i<j; i++, j-- )); do
    echo "i=$i j=$j"
done

4. Simple loop using {start..end} syntax:

for i in {1..5}
do
    echo "Number: $i"
done
[ Number: 1 ]
[ Number: 2 ]
[ Number: 3 ]
[ Number: 4 ]
[ Number: 5 ]

Brace expansion happens before the loop runs โ€” the shell expands {1..5} into 1 2 3 4 5 and the loop iterates over the resulting list.

Brace expansion also supports:

  • Step: {1..10..2} โ†’ 1 3 5 7 9
  • Letters: {a..e} โ†’ a b c d e
  • Zero-padding: {01..05} โ†’ 01 02 03 04 05
$ echo {1..5}
[ 1 2 3 4 5 ]

$ echo {1..10..2}
[ 1 3 5 7 9 ]

$ echo {a..e}
[ a b c d e ]

$ echo {01..05}
[ 01 02 03 04 05 ]

Note: Brace expansion is a bash feature. It doesn’t work in sh or dash. Also, the start and end must be literal numbers โ€” you can’t use variables directly:

# โŒ Doesn't work โ€” braces don't expand variables
start=1
end=5
for i in {$start..$end}; do ...; done

# โœ… Use seq or C-style instead
for i in $(seq "$start" "$end"); do ...; done
for ((i=start; i<=end; i++)); do ...; done

5. Loop through all .sh files in the current directory:

for file in *.sh
do
    echo "Processing file: $file"
done
[ Processing file: backup.sh ]
[ Processing file: deploy.sh ]
[ Processing file: test.sh ]

The glob *.sh is expanded by the shell into a list of matching filenames. The loop then iterates over each one.

Important: If no files match, the glob is passed literally โ€” the loop runs once with file="*.sh". Handle this with shopt -s nullglob or an existence check:

# Option 1: nullglob โ€” unmatched globs expand to nothing
shopt -s nullglob
for file in *.sh; do
    echo "$file"
done

# Option 2: existence check
for file in *.sh; do
    [ -e "$file" ] || continue
    echo "$file"
done

6. Nested loops:

for i in {1..3}
do
    for j in {1..3}
    do
        echo "i: $i, j: $j"
    done
done
[ i: 1, j: 1 ]
[ i: 1, j: 2 ]
[ i: 1, j: 3 ]
[ i: 2, j: 1 ]
[ i: 2, j: 2 ]
[ i: 2, j: 3 ]
[ i: 3, j: 1 ]
[ i: 3, j: 2 ]
[ i: 3, j: 3 ]

For each value of i, the inner loop runs through all values of j. Total iterations = outer ร— inner.

Nested loops are common for:

  • Grids and tables
  • Combinations (pairs, triples)
  • Files in multiple directories
  • Matrix-style operations

7. Loop through each line of the output from ls:

for file in $(ls)
do
    echo "File: $file"
done
[ File: backup.sh ]
[ File: documents ]
[ File: notes.txt ]
[ File: photos ]

This works โ€” $(ls) produces a list of filenames, and the loop iterates. But it’s fragile. If filenames contain spaces, $(ls) splits them into separate words and the loop breaks.

$ touch "my file.txt"
$ for file in $(ls); do echo "File: $file"; done
[ File: my ]
[ File: file.txt ]
# โŒ "my file.txt" became two items!

Better options:

# โœ… Option 1: glob โ€” handles spaces correctly
for file in *; do
    echo "File: $file"
done

# โœ… Option 2: find with null separator
while IFS= read -r -d '' file; do
    echo "File: $file"
done < <(find . -maxdepth 1 -type f -print0)

# โœ… Option 3: readarray
readarray -t files < <(ls)
for file in "${files[@]}"; do
    echo "File: $file"
done

Rule of thumb: Never use for x in $(ls). Use for x in * instead. If you need find-like behavior, use a while read loop with -print0.

More practical for loop examples:

# Iterate over command-line arguments
for arg in "$@"; do
    echo "Argument: $arg"
done

# Iterate over an array
fruits=("apple" "banana" "cherry")
for fruit in "${fruits[@]}"; do
    echo "$fruit"
done

# Loop over words from a command
for user in $(cut -d: -f1 /etc/passwd); do
    echo "User: $user"
done

# Loop over files recursively
for file in /var/log/*.log; do
    [ -e "$file" ] || continue
    echo "Log: $file"
done

# Loop with index (C-style)
files=(*.txt)
for ((i=0; i<${#files[@]}; i++)); do
    echo "$i: ${files[i]}"
done

# Rename files with a prefix
for file in *.txt; do
    mv "$file" "backup_$file"
done

# Ping a list of hosts
for host in server1 server2 server3; do
    ping -c1 "$host" > /dev/null && echo "$host: up" || echo "$host: down"
done

# Generate numbered files
for i in {1..5}; do
    touch "file$i.txt"
done

# Sum numbers from a list
sum=0
for n in 10 20 30 40; do
    ((sum += n))
done
echo "Sum: $sum"
[ Sum: 100 ]

Complete Example Session

# ============================================
# PART 1: LITERAL LIST
# ============================================

$ for i in 1 2 3 4 5; do echo "Number: $i"; done
[ Number: 1 ]
[ Number: 2 ]
[ Number: 3 ]
[ Number: 4 ]
[ Number: 5 ]

# ============================================
# PART 2: SEQ
# ============================================

$ for i in $(seq 1 5); do echo "Number: $i"; done
[ Number: 1 ]
[ Number: 2 ]
[ Number: 3 ]
[ Number: 4 ]
[ Number: 5 ]

$ for i in $(seq 0 2 10); do echo "$i"; done
[ 0 ]
[ 2 ]
[ 4 ]
[ 6 ]
[ 8 ]
[ 10 ]

# ============================================
# PART 3: C-STYLE
# ============================================

$ for (( i=1; i<=5; i++ )); do echo "Number: $i"; done
[ Number: 1 ]
[ Number: 2 ]
[ Number: 3 ]
[ Number: 4 ]
[ Number: 5 ]

$ for (( i=5; i>=1; i-- )); do echo "$i"; done
[ 5 ]
[ 4 ]
[ 3 ]
[ 2 ]
[ 1 ]

# ============================================
# PART 4: BRACE EXPANSION
# ============================================

$ for i in {1..5}; do echo "Number: $i"; done
[ Number: 1 ]
[ Number: 2 ]
[ Number: 3 ]
[ Number: 4 ]
[ Number: 5 ]

$ echo {1..10..2}
[ 1 3 5 7 9 ]

$ echo {a..e}
[ a b c d e ]

$ echo {01..05}
[ 01 02 03 04 05 ]

# ============================================
# PART 5: GLOB FILES
# ============================================

$ touch test1.sh test2.sh test3.sh
$ for file in *.sh; do echo "Processing: $file"; done
[ Processing: test1.sh ]
[ Processing: test2.sh ]
[ Processing: test3.sh ]

# ============================================
# PART 6: NESTED LOOPS
# ============================================

$ for i in {1..3}; do
>     for j in {1..3}; do
>         echo "i: $i, j: $j"
>     done
> done
[ i: 1, j: 1 ]
[ i: 1, j: 2 ]
[ i: 1, j: 3 ]
[ i: 2, j: 1 ]
[ i: 2, j: 2 ]
[ i: 2, j: 3 ]
[ i: 3, j: 1 ]
[ i: 3, j: 2 ]
[ i: 3, j: 3 ]

# ============================================
# PART 7: LS OUTPUT โ€” AND WHY IT BREAKS
# ============================================

$ for file in $(ls); do echo "File: $file"; done
[ File: test1.sh ]
[ File: test2.sh ]
[ File: test3.sh ]

$ touch "my file.txt"
$ for file in $(ls); do echo "File: $file"; done
[ File: my ]
[ File: file.txt ]
[ File: test1.sh ]
[ File: test2.sh ]
[ File: test3.sh ]
# โŒ "my file.txt" was split

$ for file in *; do echo "File: $file"; done
[ File: my file.txt ]
[ File: test1.sh ]
[ File: test2.sh ]
[ File: test3.sh ]
# โœ… glob handles spaces correctly

# ============================================
# PART 8: BREAK AND CONTINUE
# ============================================

$ for i in 1 2 3 4 5; do
>     [ $i -eq 3 ] && break
>     echo "$i"
> done
[ 1 ]
[ 2 ]

$ for i in 1 2 3 4 5; do
>     [ $i -eq 3 ] && continue
>     echo "$i"
> done
[ 1 ]
[ 2 ]
[ 4 ]
[ 5 ]

# ============================================
# PART 9: ITERATE ARGUMENTS
# ============================================

$ cat > args.sh << 'EOF'
#!/bin/bash
for arg in "$@"; do
    echo "Argument: $arg"
done
EOF
$ chmod +x args.sh
$ ./args.sh one two three
[ Argument: one ]
[ Argument: two ]
[ Argument: three ]

# ============================================
# PART 10: ITERATE ARRAY
# ============================================

$ fruits=("apple" "banana" "cherry")
$ for fruit in "${fruits[@]}"; do echo "$fruit"; done
[ apple ]
[ banana ]
[ cherry ]

$ for ((i=0; i<${#fruits[@]}; i++)); do echo "$i: ${fruits[i]}"; done
[ 0: apple ]
[ 1: banana ]
[ 2: cherry ]

# ============================================
# PART 11: LOOP OVER WORDS FROM A COMMAND
# ============================================

$ for user in $(cut -d: -f1 /etc/passwd | head -5); do
>     echo "User: $user"
> done
[ User: root ]
[ User: daemon ]
[ User: bin ]
[ User: sys ]
[ User: sync ]

# ============================================
# PART 12: RENAME FILES
# ============================================

$ touch a.txt b.txt c.txt
$ for f in *.txt; do
>     mv "$f" "old_$f"
> done
$ ls
[ old_a.txt old_b.txt old_c.txt ]

# ============================================
# PART 13: PING HOSTS
# ============================================

$ for host in 1.1.1.1 8.8.8.8 9.9.9.9; do
>     ping -c1 "$host" > /dev/null && echo "$host: up" || echo "$host: down"
> done
[ 1.1.1.1: up ]
[ 8.8.8.8: up ]
[ 9.9.9.9: up ]

# ============================================
# PART 14: GENERATE FILES
# ============================================

$ for i in {1..5}; do touch "file$i.txt"; done
$ ls file*.txt
[ file1.txt file2.txt file3.txt file4.txt file5.txt ]

# ============================================
# PART 15: SUM NUMBERS
# ============================================

$ sum=0
$ for n in 10 20 30 40; do
>     ((sum += n))
> done
$ echo "Sum: $sum"
[ Sum: 100 ]

# ============================================
# PART 16: FULL SCRIPT
# ============================================

$ cat > full.sh << 'EOF'
#!/bin/bash

for i in 1 2 3 4 5
do
    echo "Number: $i"
done

for i in $(seq 1 5)
do
    echo "Number: $i"
done

for (( i=1; i<=5; i++ ))
do
    echo "Number: $i"
done

for i in {1..5}
do
    echo "Number: $i"
done

for file in *.sh
do
    echo "Processing file: $file"
done

for i in {1..3}
do
    for j in {1..3}
    do
        echo "i: $i, j: $j"
    done
done

for file in *
do
    echo "File: $file"
done
EOF
$ chmod +x full.sh
$ ./full.sh

Quick Reference

for Loop Forms

FormSyntaxExample
Literal listfor i in a b cfor i in 1 2 3
seqfor i in $(seq N M)for i in $(seq 1 5)
C-stylefor ((i=N; i<=M; i++))for ((i=1; i<=5; i++))
Bracefor i in {N..M}for i in {1..5}
Globfor f in PATTERNfor f in *.txt
Arrayfor x in "${arr[@]}"for x in "${a[@]}"
Argsfor a in "$@"for a in "$@"
Commandfor x in $(cmd)for u in $(ls)

Brace Expansion

PatternExpands to
{1..5}1 2 3 4 5
{1..10..2}1 3 5 7 9
{a..e}a b c d e
{01..05}01 02 03 04 05
{a,b,c}a b c
{red,green,blue}red green blue

seq

CommandOutput
seq 51 2 3 4 5
seq 2 52 3 4 5
seq 0 2 100 2 4 6 8 10
seq -w 1 51 2 3 4 5 (padded)

Loop Control

CommandPurpose
breakExit the loop
continueSkip to next item
break 2Exit 2 levels (bash 4+)
continue 2Continue outer loop

Comparison

FormBest for
LiteralSmall, fixed lists
seqRanges with variables
C-styleCounters, custom steps
BraceSimple ranges with literals
GlobFiles and directories
ArrayIterating arrays
"$@"Command-line arguments

Best Practices

โœ… Do This:

# Use globs for files
for f in *.txt; do ...; done              # โœ…

# Use "$@" for arguments
for a in "$@"; do ...; done               # โœ…

# Quote array expansion
for x in "${arr[@]}"; do ...; done        # โœ…

# Use C-style for numeric loops with variables
for ((i=0; i<n; i++)); do ...; done       # โœ…

# Use brace expansion for simple ranges
for i in {1..10}; do ...; done            # โœ…

# Handle unmatched globs
shopt -s nullglob
for f in *.txt; do ...; done              # โœ…

# Check existence when necessary
for f in *.txt; do
    [ -e "$f" ] || continue
    ...
done                                      # โœ…

# Use seq when the range is dynamic
start=1; end=10
for i in $(seq "$start" "$end"); do ...; done  # โœ…

โŒ Don’t Do This:

# Don't use $(ls)
for f in $(ls); do ...; done              # โŒ breaks on spaces

# Don't use brace expansion with variables
for i in {$start..$end}; do ...; done     # โŒ doesn't expand vars

# Don't forget quotes around variables
for f in $files; do ...; done             # โš ๏ธ  word splitting

# Don't iterate over a command's output for files
for f in $(find .); do ...; done          # โŒ breaks on spaces
# Use: find . -print0 | while IFS= read -r -d '' f; do ...; done

# Don't modify the loop list inside the loop
for i in 1 2 3; do
    i=10                                  # โš ๏ธ  no effect on next iteration
done

# Don't use for when while is clearer
for ((;;)); do ...; done                  # โš ๏ธ  use while true

# Don't assume brace expansion works in sh
#!/bin/sh
for i in {1..5}; do ...; done             # โŒ not POSIX

Common Pitfalls

PitfallProblemSolution
$(ls) with spacesSplits filenamesUse for f in *
Unmatched globLiteral *.txtshopt -s nullglob
Brace with variablesDoesn’t expandUse seq or C-style
Unquoted $@Word splittingUse "$@"
Unquoted arrayWord splitting"${arr[@]}"
find outputSplits on spaces-print0 + read -d ''
Missing doneSyntax errorAdd done
Missing doSyntax errorAdd do
Modifying loop varNo effectUse a different variable
{1..5} in shNot supportedUse seq 1 5

Real-World Examples

1. Simple Loop

#!/bin/bash
for i in 1 2 3 4 5; do
    echo "Number: $i"
done
[ Number: 1 ]
[ Number: 2 ]
[ Number: 3 ]
[ Number: 4 ]
[ Number: 5 ]

2. Loop with seq

#!/bin/bash
for i in $(seq 1 5); do
    echo "Number: $i"
done

3. C-Style Loop

#!/bin/bash
for (( i=1; i<=5; i++ )); do
    echo "Number: $i"
done

4. Brace Expansion

#!/bin/bash
for i in {1..5}; do
    echo "Number: $i"
done

5. Loop Through .sh Files

#!/bin/bash
for file in *.sh; do
    echo "Processing file: $file"
done

6. Nested Loops

#!/bin/bash
for i in {1..3}; do
    for j in {1..3}; do
        echo "i: $i, j: $j"
    done
done

7. Loop Through Files (Safe)

#!/bin/bash
for file in *; do
    echo "File: $file"
done

8. Iterate Arguments

#!/bin/bash
for arg in "$@"; do
    echo "Argument: $arg"
done

9. Iterate Array

#!/bin/bash
fruits=("apple" "banana" "cherry")
for fruit in "${fruits[@]}"; do
    echo "$fruit"
done

10. Iterate with Index

#!/bin/bash
fruits=("apple" "banana" "cherry")
for ((i=0; i<${#fruits[@]}; i++)); do
    echo "$i: ${fruits[i]}"
done

11. Rename Files with Prefix

#!/bin/bash
for f in *.txt; do
    mv "$f" "backup_$f"
done

12. Ping a List of Hosts

#!/bin/bash
for host in server1 server2 server3; do
    if ping -c1 "$host" > /dev/null 2>&1; then
        echo "$host: up"
    else
        echo "$host: down"
    fi
done

13. Generate Numbered Files

#!/bin/bash
for i in {1..10}; do
    touch "file$i.txt"
done

14. Sum a List of Numbers

#!/bin/bash
sum=0
for n in 10 20 30 40 50; do
    ((sum += n))
done
echo "Sum: $sum"
[ Sum: 150 ]

15. Loop Over Words from Command

#!/bin/bash
for user in $(cut -d: -f1 /etc/passwd | head -10); do
    echo "User: $user"
done

16. Recursive Directory Walk

#!/bin/bash
for dir in */; do
    echo "Directory: $dir"
    for file in "$dir"*; do
        echo "  File: $file"
    done
done

17. Generate a Times Table

#!/bin/bash
for i in {1..5}; do
    for j in {1..5}; do
        printf "%4d" $((i * j))
    done
    echo
done

18. Convert Files with ffmpeg

#!/bin/bash
for video in *.mp4; do
    ffmpeg -i "$video" "${video%.mp4}.webm"
done

19. Clean Up Old Files

#!/bin/bash
for f in /tmp/script.*; do
    [ -e "$f" ] || continue
    [ "$f" -ot /tmp/keep ] && rm -f "$f"
done

20. Full Example

#!/bin/bash

for i in 1 2 3 4 5
do
    echo "Number: $i"
done

for i in $(seq 1 5)
do
    echo "Number: $i"
done

for (( i=1; i<=5; i++ ))
do
    echo "Number: $i"
done

for i in {1..5}
do
    echo "Number: $i"
done

for file in *.sh
do
    echo "Processing file: $file"
done

for i in {1..3}
do
    for j in {1..3}
    do
        echo "i: $i, j: $j"
    done
done

for file in *
do
    echo "File: $file"
done

Visual: Five Ways to Iterate

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚           Literal list                       โ”‚
โ”‚  for i in 1 2 3 4 5; do ...; done           โ”‚
โ”‚                                              โ”‚
โ”‚  i โ†’ 1, 2, 3, 4, 5                           โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚           seq                                โ”‚
โ”‚  for i in $(seq 1 5); do ...; done          โ”‚
โ”‚                                              โ”‚
โ”‚  seq 1 5  โ†’ "1 2 3 4 5"                     โ”‚
โ”‚  i โ†’ 1, 2, 3, 4, 5                           โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚           C-style                            โ”‚
โ”‚  for ((i=1; i<=5; i++)); do ...; done       โ”‚
โ”‚                                              โ”‚
โ”‚  init: i=1                                   โ”‚
โ”‚  test: i<=5                                  โ”‚
โ”‚  incr: i++                                   โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚           Brace expansion                    โ”‚
โ”‚  for i in {1..5}; do ...; done              โ”‚
โ”‚                                              โ”‚
โ”‚  {1..5} โ†’ "1 2 3 4 5"                       โ”‚
โ”‚  i โ†’ 1, 2, 3, 4, 5                           โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚           Glob                               โ”‚
โ”‚  for f in *.txt; do ...; done               โ”‚
โ”‚                                              โ”‚
โ”‚  *.txt โ†’ "a.txt b.txt c.txt"                โ”‚
โ”‚  f โ†’ a.txt, b.txt, c.txt                     โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Visual: Nested Loops

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  for i in {1..3}; do                         โ”‚
โ”‚      for j in {1..3}; do                     โ”‚
โ”‚          echo "$i, $j"                       โ”‚
โ”‚      done                                    โ”‚
โ”‚  done                                        โ”‚
โ”‚                                              โ”‚
โ”‚  Iterations:                                 โ”‚
โ”‚  i=1 โ†’ j=1, j=2, j=3                         โ”‚
โ”‚  i=2 โ†’ j=1, j=2, j=3                         โ”‚
โ”‚  i=3 โ†’ j=1, j=2, j=3                         โ”‚
โ”‚                                              โ”‚
โ”‚  Total: 3 ร— 3 = 9 iterations                 โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

FormSyntaxExample
Literalfor i in 1 2 3for i in a b c
seqfor i in $(seq 1 5)for i in $(seq 0 2 10)
C-stylefor ((i=1; i<=5; i++))for ((i=5; i>=1; i--))
Bracefor i in {1..5}for i in {a..e}
Globfor f in *.txtfor f in *
Arrayfor x in "${a[@]}"for x in "${fruits[@]}"
Argsfor a in "$@"for a in "$@"
BreakbreakExit early
ContinuecontinueSkip one
Break Nbreak 2Exit N levels

Key takeaways:

  • for iterates over a known list โ€” of words, numbers, files, array items, or arguments
  • Five forms: literal list, seq, C-style, brace expansion, and glob
  • C-style (for ((...))) is best for numeric loops with counters or custom steps
  • Brace expansion ({1..5}) is the shortest form but doesn’t work with variables
  • Globs (*.txt) are the right way to iterate files โ€” they handle spaces correctly
  • "$@" is the correct way to iterate command-line arguments
  • "${arr[@]}" is the correct way to iterate arrays
  • Never use $(ls) โ€” it breaks on filenames with spaces. Use for f in *
  • Use shopt -s nullglob or [ -e "$f" ] to handle unmatched globs
  • break and continue work the same as in while loops
  • Nested loops multiply โ€” outer ร— inner iterations
  • For dynamic ranges, use seq or C-style โ€” braces only accept literals

Remember: for is the loop for iterating known lists. Use globs for files, "$@" for arguments, arrays for grouped data, and C-style when you need numeric control. Avoid $(ls) โ€” it’s a trap. Handle unmatched globs. And when you need to wait for something or loop on a condition, reach for while or until instead.

Was this helpful?


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!