Loop_control
Chapter 10: Loop Control (break, continue)
Section titled “Chapter 10: Loop Control (break, continue)”Overview
Section titled “Overview”This chapter covers the control statements that modify loop behavior: break and continue. These statements provide fine-grained control over loop execution, enabling complex logic patterns commonly needed in DevOps scripts for error handling, search operations, and state machine implementations.
The break Statement
Section titled “The break Statement”Basic break
Section titled “Basic break”The break statement immediately exits the innermost loop.
#!/usr/bin/env bash# Find first matching filefor file in /tmp/*.txt; do echo "Checking: $file"
if [ -s "$file" ]; then echo "Found non-empty file: $file" break # Exit loop fidonebreak with Numeric Argument
Section titled “break with Numeric Argument”You can specify how many loop levels to break out of.
#!/usr/bin/env bash# Break out of multiple loopsfor i in {1..3}; do echo "Outer loop: $i"
for j in {1..3}; do echo " Inner loop: $j"
if [ $j -eq 2 ]; then break 2 # Break out of both loops fi donedoneThe continue Statement
Section titled “The continue Statement”Basic continue
Section titled “Basic continue”The continue statement skips the rest of the current iteration and moves to the next iteration.
#!/usr/bin/env bash# Skip even numbersfor i in {1..10}; do if [ $((i % 2)) -eq 0 ]; then continue # Skip this iteration fi echo "Odd number: $i"donecontinue with Label
Section titled “continue with Label”You can continue to a specific loop level using labels.
#!/usr/bin/env bash# Continue to outer loopfor i in {1..3}; do for j in {1..3}; do if [ $j -eq 2 ]; then continue # Continue inner loop fi echo "i=$i, j=$j" donedone
echo "---"
# Using labelouter_loop:for i in {1..3}; do for j in {1..3}; do if [ $j -eq 2 ]; then continue outer_loop # Continue outer loop fi echo "i=$i, j=$j" donedoneLoop Control Patterns
Section titled “Loop Control Patterns”Find First Match
Section titled “Find First Match”#!/usr/bin/env bash# Pattern: Find first matching itemservices=("nginx" "mysql" "redis" "postgresql")
for service in "${services[@]}"; do if systemctl is-active --quiet "$service"; then echo "Found active service: $service" break fidoneProcess Until Condition Met
Section titled “Process Until Condition Met”#!/usr/bin/env bash# Pattern: Process until condition is metcount=0max_iterations=10
while true; do count=$((count + 1)) echo "Processing iteration: $count"
# Simulate work sleep 1
if [ $count -ge $max_iterations ]; then echo "Maximum iterations reached" break fidoneSkip Invalid Items
Section titled “Skip Invalid Items”#!/usr/bin/env bash# Pattern: Skip invalid items in processingfiles=( "/etc/passwd" "/nonexistent/file1.txt" "/etc/hosts" "/nonexistent/file2.txt" "/etc/fstab")
for file in "${files[@]}"; do # Skip if file doesn't exist if [ ! -f "$file" ]; then echo "Skipping (not found): $file" continue fi
# Process valid file lines=$(wc -l < "$file") echo "Processed: $file ($lines lines)"doneCount Success/Failure
Section titled “Count Success/Failure”#!/usr/bin/env bash# Pattern: Count successes and failuresservers=("server1" "server2" "server3" "server4")
success=0failure=0
for server in "${servers[@]}"; do if ping -c 1 -W 2 "$server" &>/dev/null; then echo "✓ $server is reachable" success=$((success + 1)) else echo "✗ $server is not reachable" failure=$((failure + 1)) fidone
echo "---"echo "Success: $success"echo "Failure: $failure"Practical Examples
Section titled “Practical Examples”Example 1: Search for Pattern in Files
Section titled “Example 1: Search for Pattern in Files”#!/usr/bin/env bashset -euo pipefail
# Search for pattern in files, stop after first matchsearch_pattern="$1"search_dir="${2:-.}"
if [ -z "$search_pattern" ]; then echo "Usage: $0 <pattern> [directory]" exit 1fi
echo "Searching for '$search_pattern' in $search_dir..."
for file in $(find "$search_dir" -type f -name "*.log" 2>/dev/null); do if grep -q "$search_pattern" "$file"; then echo "Found in: $file" echo "Content:" grep "$search_pattern" "$file" break # Stop after first match fidoneExample 2: Retry with Timeout
Section titled “Example 2: Retry with Timeout”#!/usr/bin/env bashset -euo pipefail
# Function to simulate a command that might failattempt_command() { local attempt=$1 echo "Attempt $attempt..."
# Simulate occasional failure if [ $((attempt % 3)) -ne 0 ]; then return 1 fi return 0}
# Retry loop with timeoutmax_attempts=10attempt=0
while [ $attempt -lt $max_attempts ]; do attempt=$((attempt + 1))
if attempt_command $attempt; then echo "Success on attempt $attempt" exit 0 fi
echo "Attempt $attempt failed, retrying in 2 seconds..." sleep 2done
echo "Failed after $max_attempts attempts"exit 1Example 3: Process with Error Limit
Section titled “Example 3: Process with Error Limit”#!/usr/bin/env bashset -euo pipefail
# Process items, stop after too many errorsitems=(item1 item2 item3 item4 item5)max_errors=2
errors=0processed=0
for item in "${items[@]}"; do # Check error limit if [ $errors -ge $max_errors ]; then echo "Error limit reached ($max_errors), stopping" break fi
echo "Processing: $item"
# Simulate processing (randomly succeed/fail) if [ $((RANDOM % 2)) -eq 0 ]; then echo " ✓ Success" processed=$((processed + 1)) else echo " ✗ Failed" errors=$((errors + 1)) fidone
echo "---"echo "Processed: $processed"echo "Errors: $errors"Example 4: Menu with Exit
Section titled “Example 4: Menu with Exit”#!/usr/bin/env bash# Interactive menu with exit optionwhile true; do echo "=== Menu ===" echo "1. Option A" echo "2. Option B" echo "3. Option C" echo "4. Exit" echo "============"
read -p "Choice: " choice
case "$choice" in 1) echo "Selected Option A" ;; 2) echo "Selected Option B" ;; 3) echo "Selected Option C" ;; 4) echo "Exiting..." break # Exit the loop ;; *) echo "Invalid choice" ;; esac
echo ""doneExample 5: Process Logs Until Critical Error
Section titled “Example 5: Process Logs Until Critical Error”#!/usr/bin/env bashset -euo pipefail
# Read log lines, process until critical errorlog_file="${1:-/var/log/syslog}"
if [ ! -f "$log_file" ]; then echo "Log file not found: $log_file" exit 1fi
error_count=0critical_found=false
while IFS= read -r line; do if echo "$line" | grep -q "CRITICAL"; then echo "CRITICAL error found!" echo "$line" critical_found=true break # Stop on critical error elif echo "$line" | grep -q "ERROR"; then error_count=$((error_count + 1)) echo "ERROR: $line" else # Process other lines : fidone < "$log_file"
echo "---"echo "Processed until first critical error"echo "Errors found: $error_count"Example 6: Skip Hidden Files
Section titled “Example 6: Skip Hidden Files”#!/usr/bin/env bash# Process directory, skip hidden files and directoriesdir="${1:-.}"
for item in "$dir"/*; do # Skip if doesn't exist (nullglob) [ -e "$item" ] || continue
# Get basename name=$(basename "$item")
# Skip hidden files if [[ "$name" == .* ]]; then continue fi
# Process if [ -d "$item" ]; then echo "Directory: $name" elif [ -f "$item" ]; then echo "File: $name" fidoneAdvanced Patterns
Section titled “Advanced Patterns”Nested Loop with break
Section titled “Nested Loop with break”#!/usr/bin/env bash# Search in 3D gridfound=false
for x in {1..3}; do for y in {1..3}; do for z in {1..3}; do echo "Checking ($x, $y, $z)"
# Simulate finding target at (2, 2, 2) if [ $x -eq 2 ] && [ $y -eq 2 ] && [ $z -eq 2 ]; then echo "Found at ($x, $y, $z)" found=true break 3 # Break out of all three loops fi done donedone
if [ "$found" = true ]; then echo "Search complete - found"else echo "Search complete - not found"fiContinue with Counter
Section titled “Continue with Counter”#!/usr/bin/env bash# Process items, skip some based on counteritems=(a b c d e f g h i j)skip_count=3current_skip=0
for item in "${items[@]}";do # Skip every Nth item current_skip=$((current_skip + 1)) if [ $current_skip -eq $skip_count ]; then current_skip=0 echo "Skipping: $item" continue fi
echo "Processing: $item"doneBreak and Continue in Functions
Section titled “Break and Continue in Functions”#!/usr/bin/env bash# Using return to exit loops in functionsfind_in_array() { local needle="$1" shift local haystack=("$@")
for i in "${!haystack[@]}"; do if [ "${haystack[$i]}" = "$needle" ]; then return $i # Return index fi done
return 255 # Not found}
# Testarray=("apple" "banana" "cherry" "date")
find_in_array "cherry" "${array[@]}"result=$?
if [ $result -eq 255 ]; then echo "Not found"else echo "Found at index: $result"fiCommon Mistakes
Section titled “Common Mistakes”Forgetting break in Infinite Loop
Section titled “Forgetting break in Infinite Loop”#!/usr/bin/env bash# WRONG: Infinite loop without breakcounter=0while true; do echo "Counter: $counter" counter=$((counter + 1)) # Missing break - infinite loop!done
# CORRECT: Always have exit conditioncounter=0while true; do echo "Counter: $counter" counter=$((counter + 1)) if [ $counter -ge 10 ]; then break fidoneContinue Without Proper Skipping
Section titled “Continue Without Proper Skipping”#!/usr/bin/env bash# WRONG: Continue inside nested structurefor i in {1..5}; do echo "Outer: $i" { continue # This will error or behave unexpectedly }done
# CORRECT: Use proper structurefor i in {1..5}; do if [ $i -eq 3 ]; then continue # Skip iteration fi echo "Value: $i"doneSummary
Section titled “Summary”In this chapter, you learned about:
- ✅ The break statement basics
- ✅ Breaking out of multiple levels
- ✅ The continue statement basics
- ✅ Continuing with labels
- ✅ Common loop control patterns
- ✅ Find first match pattern
- ✅ Process until condition pattern
- ✅ Skip invalid items pattern
- ✅ Count success/failure pattern
- ✅ Practical DevOps examples
- ✅ Advanced nested loop patterns
- ✅ Common mistakes and corrections
Exercises
Section titled “Exercises”Level 1: Basics
Section titled “Level 1: Basics”- Write a script that finds the first file matching a pattern
- Create a script that skips even numbers in a loop
- Write a menu system using break
Level 2: Intermediate
Section titled “Level 2: Intermediate”- Implement a retry mechanism with break
- Create a script that processes until error limit
- Write a log processor that stops on critical error
Level 3: Advanced
Section titled “Level 3: Advanced”- Implement a search in multidimensional data
- Create a concurrent worker with error handling
- Build a state machine using loop control
Next Steps
Section titled “Next Steps”Continue to the next chapter to learn about arrays in bash.