Bash Loops

Repeating tasks efficiently in your scripts

πŸ” What are Bash Loops?

Loops repeat a block of code multiple times automatically. They save you from writing the same code over and over, making your scripts shorter and more efficient for repetitive tasks.


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

Output:

Number: 1
Number: 2
Number: 3
Number: 4
Number: 5

Types of Loops

πŸ”„

For Loop

Iterate over a list

for item in list
do
    # code
done
⏰

While Loop

Loop while condition is true

while [ condition ]
do
    # code
done
πŸ”‚

Until Loop

Loop until condition is true

until [ condition ]
do
    # code
done
🎯

Loop Control

Break and continue

break
continue

πŸ”Ή For Loop

The for loop iterates over a list of items, executing commands for each one. Syntax: for item in list; do commands; done. The list can be explicit words (a b c), a variable expansion, or command output ($(ls *.txt)). It's perfect when you know the set of items to process. The loop variable (item) takes each value sequentially. For example, for file in *.log; do echo "Processing $file"; done. It's a fundamental tool for batch operations, data processing, and automation of repetitive tasks.

#!/bin/bash

# Loop through numbers
echo "Counting:"
for num in 1 2 3 4 5
do
    echo "Count: $num"
done

# Loop through strings
echo -e "\nFruits:"
for fruit in Apple Banana Orange
do
    echo "I like $fruit"
done

# Loop with range
echo -e "\nRange 1 to 5:"
for i in {1..5}
do
    echo "Number $i"
done

# Loop through files
echo -e "\nText files:"
for file in *.txt
do
    echo "Found: $file"
done

Output:

Counting:
Count: 1
Count: 2
Count: 3
Count: 4
Count: 5

Fruits:
I like Apple
I like Banana
I like Orange

Range 1 to 5:
Number 1
Number 2
Number 3
Number 4
Number 5

Text files:
Found: data.txt
Found: notes.txt

πŸ”Ή C-Style For Loop

C-style for loops use a three-expression syntax for precise iteration control: initialization, condition, and increment. Written as for (( i=0; i<10; i++ )); do commands; done. This format, familiar from languages like C or Java, is ideal for numeric loops where you control the start, end, and step value. It's more flexible than the simple for...in loop for arithmetic progressions. Example: counting down for (( i=5; i>0; i-- )). The expressions are evaluated in an arithmetic context, allowing complex conditions.

#!/bin/bash

# Basic C-style loop
echo "Count to 5:"
for ((i=1; i<=5; i++))
do
    echo "i = $i"
done

# Loop with step
echo -e "\nEven numbers:"
for ((n=0; n<=10; n+=2))
do
    echo "Even: $n"
done

# Countdown
echo -e "\nCountdown:"
for ((count=5; count>=1; count--))
do
    echo "$count..."
done
echo "Blast off!"

# Multiplication table
echo -e "\nTable of 3:"
for ((i=1; i<=5; i++))
do
    result=$((3 * i))
    echo "3 x $i = $result"
done

Output:

Count to 5:
i = 1
i = 2
i = 3
i = 4
i = 5

Even numbers:
Even: 0
Even: 2
Even: 4
Even: 6
Even: 8
Even: 10

Countdown:
5...
4...
3...
2...
1...
Blast off!

Table of 3:
3 x 1 = 3
3 x 2 = 6
3 x 3 = 9
3 x 4 = 12
3 x 5 = 15

πŸ”Ή While Loop

The while loop repeats a block of commands as long as its control condition remains true. Structure: while [ condition ]; do commands; done. The condition is checked before each iteration; if false initially, the loop never runs. It's ideal when the number of iterations isn't known beforehand, like reading a file line-by-line until the end or waiting for a condition to change. For example, while [[ ! -f /tmp/ready.txt ]]; do sleep 1; done polls for a file. Ensure the condition eventually becomes false to avoid infinite loops.

#!/bin/bash

# Basic while loop
counter=1
echo "Counting with while:"
while [ $counter -le 5 ]
do
    echo "Counter: $counter"
    counter=$((counter + 1))
done

# Reading user input
echo -e "\nGuess the number (1-10):"
secret=7
guess=0
attempts=0

while [ $guess -ne $secret ]
do
    read -p "Enter your guess: " guess
    attempts=$((attempts + 1))
    
    if [ $guess -lt $secret ]; then
        echo "Too low!"
    elif [ $guess -gt $secret ]; then
        echo "Too high!"
    fi
done

echo "Correct! You guessed in $attempts attempts"

# Reading file line by line
echo -e "\nReading file:"
while read line
do
    echo "Line: $line"
done < data.txt

Output:

Counting with while:
Counter: 1
Counter: 2
Counter: 3
Counter: 4
Counter: 5

Guess the number (1-10):
Enter your guess: 5
Too low!
Enter your guess: 8
Too high!
Enter your guess: 7
Correct! You guessed in 3 attempts

Reading file:
Line: First line of file
Line: Second line of file
Line: Third line of file

πŸ”Ή Until Loop

The until loop runs until its condition becomes trueβ€”the opposite of while. Syntax: until [ condition ]; do commands; done. The loop continues as long as the condition evaluates to false. It's useful for waiting on a desired state. For example, until ping -c1 server.com; do echo "Waiting for server..."; sleep 5; done retries until a ping succeeds. Like while, ensure the condition will eventually become true to prevent hanging. It often makes intentions clearer when the logic is "repeat until something happens."

#!/bin/bash

# Basic until loop
num=1
echo "Until loop example:"
until [ $num -gt 5 ]
do
    echo "Number: $num"
    num=$((num + 1))
done

# Wait until file exists
echo -e "\nWaiting for file..."
filename="ready.txt"
seconds=0

until [ -f "$filename" ]
do
    echo "Waiting... ($seconds seconds)"
    sleep 1
    seconds=$((seconds + 1))
    
    # Create file after 3 seconds (simulation)
    if [ $seconds -eq 3 ]; then
        touch "$filename"
    fi
done

echo "File found!"

# Countdown until zero
echo -e "\nCountdown:"
count=5
until [ $count -eq 0 ]
do
    echo "$count"
    count=$((count - 1))
    sleep 1
done
echo "Done!"

Output:

Until loop example:
Number: 1
Number: 2
Number: 3
Number: 4
Number: 5

Waiting for file...
Waiting... (0 seconds)
Waiting... (1 seconds)
Waiting... (2 seconds)
File found!

Countdown:
5
4
3
2
1
Done!

πŸ”Ή Loop Control: Break and Continue

Use break to exit a loop immediately and continue to skip to the next iteration. The break statement terminates the innermost loop, useful when a target is found or an error occurs. continue stops the current iteration and jumps to the loop's condition check, handy for skipping invalid items. For example, in a file processing loop, continue can skip empty files, while break can stop if a critical error is detected. These commands provide fine-grained control over loop execution flow, enhancing efficiency and logic.

#!/bin/bash

# Break example
echo "Break example - stop at 3:"
for i in {1..5}
do
    if [ $i -eq 3 ]; then
        echo "Breaking at $i"
        break
    fi
    echo "Number: $i"
done

# Continue example
echo -e "\nContinue example - skip 3:"
for i in {1..5}
do
    if [ $i -eq 3 ]; then
        echo "Skipping $i"
        continue
    fi
    echo "Number: $i"
done

# Practical example: find first even number
echo -e "\nFind first even number:"
for num in 1 3 5 8 9 10
do
    if [ $((num % 2)) -eq 0 ]; then
        echo "First even number: $num"
        break
    fi
done

# Skip negative numbers
echo -e "\nProcess only positive:"
for val in -2 5 -1 8 -3 10
do
    if [ $val -lt 0 ]; then
        continue
    fi
    echo "Processing: $val"
done

Output:

Break example - stop at 3:
Number: 1
Number: 2
Breaking at 3

Continue example - skip 3:
Number: 1
Number: 2
Skipping 3
Number: 4
Number: 5

Find first even number:
First even number: 8

Process only positive:
Processing: 5
Processing: 8
Processing: 10

πŸ”Ή Nested Loops

Nested loops consist of one loop inside another, creating multi-dimensional iteration. The inner loop completes all its cycles for each single iteration of the outer loop. This is ideal for working with grids, combinations, or hierarchical data (like directories within directories). For example, to generate coordinate pairs: for x in {1..3}; do for y in {1..2}; do echo "($x, $y)"; done; done. While powerful, deeply nested loops can impact performance and readability. Use them judiciously and consider if the problem can be solved with flatter logic or external tools.

#!/bin/bash

# Multiplication table
echo "Multiplication Table:"
for i in {1..3}
do
    for j in {1..3}
    do
        result=$((i * j))
        echo -n "$i x $j = $result  "
    done
    echo ""
done

# Pattern printing
echo -e "\nStar pattern:"
for i in {1..4}
do
    for j in $(seq 1 $i)
    do
        echo -n "* "
    done
    echo ""
done

# Nested loop with arrays
echo -e "\nCombinations:"
colors=("Red" "Blue")
sizes=("Small" "Large")

for color in "${colors[@]}"
do
    for size in "${sizes[@]}"
    do
        echo "$size $color"
    done
done

Output:

Multiplication Table:
1 x 1 = 1  1 x 2 = 2  1 x 3 = 3  
2 x 1 = 2  2 x 2 = 4  2 x 3 = 6  
3 x 1 = 3  3 x 2 = 6  3 x 3 = 9  

Star pattern:
* 
* * 
* * * 
* * * * 

Combinations:
Small Red
Large Red
Small Blue
Large Blue

🧠 Test Your Knowledge

Which keyword is used to skip the current iteration in a loop?