Until Loops and Loop Control
The until loop is the opposite of while - it runs until a condition becomes true. This lesson also covers loop control statements for fine-grained control.
Until Loop Syntax
until [ condition ]; do
commands
done
The loop runs until the condition becomes true (while it's false).
Until vs While
These are logically opposite:
# While: loop while true
while [ "$COUNT" -lt 5 ]; do
echo $COUNT
COUNT=$((COUNT + 1))
done
# Until: loop until true (same result)
until [ "$COUNT" -ge 5 ]; do
echo $COUNT
COUNT=$((COUNT + 1))
done
When to Use Until
Until is more readable when waiting for something to happen:
#!/bin/bash
# Wait until file exists
until [ -f "ready.flag" ]; do
echo "Waiting for ready.flag..."
sleep 1
done
echo "File found! Continuing..."
#!/bin/bash
# Wait for process to end
until [ -z "$(pgrep -x process_name)" ]; do
echo "Waiting for process to finish..."
sleep 2
done
echo "Process completed!"
Exercise: Until Loop
Use an until loop:
Waiting for Services
A practical until example:
#!/bin/bash
# Wait for server to be ready
MAX_WAIT=30
WAITED=0
until curl -s http://localhost:8080/health > /dev/null 2>&1; do
if [ $WAITED -ge $MAX_WAIT ]; then
echo "Timeout waiting for server"
exit 1
fi
echo "Waiting for server... ($WAITED seconds)"
sleep 1
WAITED=$((WAITED + 1))
done
echo "Server is ready!"
The break Statement
Exit a loop immediately:
#!/bin/bash
for i in {1..10}; do
if [ $i -eq 5 ]; then
echo "Breaking at $i"
break
fi
echo "Number: $i"
done
echo "Loop ended"
Output:
Number: 1
Number: 2
Number: 3
Number: 4
Breaking at 5
Loop ended
Breaking from Nested Loops
Break with a number to exit multiple levels:
#!/bin/bash
for i in {1..3}; do
for j in {1..3}; do
if [ $j -eq 2 ]; then
break 2 # Break both loops
fi
echo "i=$i, j=$j"
done
done
echo "Done"
# break 1 = current loop (default)
# break 2 = current + one outer loop
# break 3 = current + two outer loops
Exercise: Break Loop
Use break to exit early:
The continue Statement
Skip to the next iteration:
#!/bin/bash
for i in {1..5}; do
if [ $i -eq 3 ]; then
continue # Skip 3
fi
echo "Number: $i"
done
Output:
Number: 1
Number: 2
Number: 4
Number: 5
Skipping in Nested Loops
Continue with a number:
#!/bin/bash
for i in {1..3}; do
for j in {1..3}; do
if [ $j -eq 2 ]; then
continue 2 # Continue outer loop
fi
echo "i=$i, j=$j"
done
done
Practical continue Example
Skip invalid data:
#!/bin/bash
# Process files, skip directories
for item in *; do
if [ -d "$item" ]; then
echo "Skipping directory: $item"
continue
fi
echo "Processing file: $item"
# ... process file
done
Exercise: Skip Item
Use continue to skip an item:
Combining break and continue
#!/bin/bash
# Find first file larger than 1MB
for file in *; do
# Skip directories
if [ -d "$file" ]; then
continue
fi
SIZE=$(stat -f%z "$file" 2>/dev/null || stat -c%s "$file" 2>/dev/null)
if [ "$SIZE" -gt 1048576 ]; then
echo "Found large file: $file"
break
fi
done
Loop with else (Not Standard)
Unlike Python, bash doesn't have loop-else. Use a flag:
#!/bin/bash
FOUND=false
for file in *.txt; do
if grep -q "pattern" "$file"; then
echo "Found in: $file"
FOUND=true
break
fi
done
if [ "$FOUND" = false ]; then
echo "Pattern not found in any file"
fi
Select Loop for Menus
A special loop for creating menus:
#!/bin/bash
PS3="Choose an option: " # Custom prompt
select option in "Option 1" "Option 2" "Option 3" "Quit"; do
case $option in
"Option 1") echo "You chose 1" ;;
"Option 2") echo "You chose 2" ;;
"Option 3") echo "You chose 3" ;;
"Quit") break ;;
*) echo "Invalid option" ;;
esac
done
The select loop:
- Displays numbered menu automatically
- Sets
$REPLYto the number entered - Sets the loop variable to the selected text
- Loops until
break
Loop Control Summary
| Statement | Effect |
|---|---|
break | Exit current loop |
break N | Exit N levels of nested loops |
continue | Skip to next iteration |
continue N | Skip to next iteration of Nth outer loop |
Infinite Loop Patterns
# Method 1: while true
while true; do
# commands
done
# Method 2: while :
while :; do
# commands
done
# Method 3: until false
until false; do
# commands
done
# Method 4: for ever
for ((;;)); do
# commands
done
Best Practices
- Use until for "wait for" scenarios: More readable intent
- Always have a break condition: In infinite loops
- Use continue early: Skip items at the start of loop body
- Avoid deep nesting: Refactor with functions
- Comment break/continue N: When breaking multiple levels
# Good: clear exit condition
until [ -f "done.flag" ]; do
sleep 1
done
# Good: early continue
for file in *; do
[ -d "$file" ] && continue # Skip directories
process "$file"
done
# Good: commented multi-level break
for i in ...; do
for j in ...; do
if [ condition ]; then
break 2 # Exit both loops
fi
done
done
Key Takeaways
untilloops while condition is false (opposite ofwhile)- Use
untilwhen waiting for something to become true breakexits the loop immediatelybreak Nexits N levels of nested loopscontinueskips to the next iterationcontinue Ncontinues the Nth outer loopselectcreates interactive menus automatically- Always ensure infinite loops have a
breakcondition

