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