How to Loop Until Condition
Quick Answer: Loop Until Condition in Bash
Use the until loop to repeat commands until a condition becomes true. Syntax: until [ condition ]; do commands; done. It’s the opposite of while - keep running while the condition is false. Use until when your logic is naturally negative (loop until X is true).
Quick Comparison: Loop Types
| Type | Continues While | Syntax | Best For |
|---|---|---|---|
| while | Condition is true | while [ cond ]; do | Positive conditions |
| until | Condition is false | until [ cond ]; do | Negative conditions |
| for | Items remain | for item in list; do | Iteration over items |
| Numeric for | Counter < limit | for ((i=0; i<n; i++)) | Counted loops |
Bottom line: Use until when it makes your condition logic clearer. Otherwise use while - they’re essentially equivalent with inverted logic.
Understanding Until Loops
An until loop runs repeatedly until a condition becomes true. It’s the opposite of a while loop - where while continues as long as a condition is true, until continues as long as a condition is false.
Think of it like this:
while= “Keep running while this is true”until= “Keep running until this becomes true”
They’re essentially the same thing with opposite logic, so you can usually use either one.
Basic Until Loop Syntax
until [ condition ]; do
# Commands to repeat
done
The loop runs until the condition becomes true.
Simple Example
#!/bin/bash
# Count from 0 to 4
count=0
until [ $count -ge 5 ]; do
echo "Count: $count"
((count++))
done
Output:
Count: 0
Count: 1
Count: 2
Count: 3
Count: 4
This is equivalent to:
while [ $count -lt 5 ]; do
# same code
done
When to Use Simple Until Loops
- You’re counting to a limit
- The condition is simpler expressed as “until X”
- You need a straightforward loop with counter
Practical Examples
Real-World Example: Wait for Service
#!/bin/bash
# Wait until a service is running
SERVICE="nginx"
MAX_ATTEMPTS=30
ATTEMPT=0
until systemctl is-active --quiet "$SERVICE" || [ $ATTEMPT -ge $MAX_ATTEMPTS ]; do
echo "Waiting for $SERVICE to start... ($ATTEMPT/$MAX_ATTEMPTS)"
sleep 2
((ATTEMPT++))
done
if systemctl is-active --quiet "$SERVICE"; then
echo "$SERVICE is running"
else
echo "ERROR: $SERVICE failed to start"
exit 1
fi
When to Use Service Wait Pattern
- You’re starting a service and need to wait for it
- You have a timeout to prevent infinite waits
- You need to check service status repeatedly
Until with Multiple Conditions
#!/bin/bash
# Wait until file is readable and contains data
filename="/tmp/ready.txt"
until [[ -f "$filename" && -s "$filename" ]]; do
echo "Waiting for file: $filename"
sleep 1
done
echo "File is ready:"
cat "$filename"
When to Use Multiple Conditions
- You’re waiting for multiple things to be ready
- You need complex readiness checks
- You’re orchestrating several conditions
Retry Logic
#!/bin/bash
download_file() {
local url="$1"
local output="$2"
local max_retries=5
local retry=0
until [[ -f "$output" ]] || (( retry >= max_retries )); do
echo "Attempt $((retry + 1)) of $max_retries: Downloading $url"
wget -q "$url" -O "$output"
if [[ -f "$output" ]]; then
echo "Download successful"
return 0
fi
echo "Download failed, retrying..."
((retry++))
sleep 2
done
if [[ ! -f "$output" ]]; then
echo "ERROR: Failed to download after $max_retries attempts"
return 1
fi
}
download_file "https://example.com/data.zip" "/tmp/data.zip"
When to Use Retry Pattern
- You’re downloading files over a network
- You want automatic retry on failure
- You have a maximum retry count
- You want delays between retries
Using until with break
You can still use break to exit early:
#!/bin/bash
counter=0
until false; do # This loop would never end naturally
((counter++))
echo "Iteration: $counter"
if (( counter == 5 )); then
echo "Breaking out"
break
fi
done
When to Use Break in Until
- You have a natural exit condition
- You want to stop the loop early
- You’re implementing safeguards
When to Use Until
Use until when:
- Your condition is “keep running until this becomes true”
- The logic is clearer with a negative condition
Example:
# Clear and natural with until
until [ "$user_input" = "quit" ]; do
read -p "Enter command (quit to exit): " user_input
# process command
done
# Less intuitive with while
while [ "$user_input" != "quit" ]; do
read -p "Enter command (quit to exit): " user_input
# process command
done
Quick Reference
# Until: Continue until x > 5
count=0
until [ $count -gt 5 ]; do
echo $count
((count++))
done
# While: Continue while x <= 5
count=0
while [ $count -le 5 ]; do
echo $count
((count++))
done
# Both produce the same output
Comparison of until and while:
# Until: Continue until x > 5
count=0
until [ $count -gt 5 ]; do
echo $count
((count++))
done
# While: Continue while x <= 5
count=0
while [ $count -le 5 ]; do
echo $count
((count++))
done
Health Check Loop Example
#!/bin/bash
check_system_health() {
local max_checks=10
local check_num=0
local cpu_ok=false
local memory_ok=false
until ([[ "$cpu_ok" == true ]] && [[ "$memory_ok" == true ]]) || (( check_num >= max_checks )); do
# Check CPU usage (simplified - under 80%)
cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print 100 - $8}' | cut -d. -f1)
if (( cpu_usage < 80 )); then
cpu_ok=true
fi
# Check memory usage (simplified - under 80%)
memory_usage=$(free | grep Mem | awk '{printf("%d", $3/$2 * 100)}')
if (( memory_usage < 80 )); then
memory_ok=true
fi
echo "Check $((check_num + 1)): CPU=$cpu_ok, Memory=$memory_ok"
((check_num++))
sleep 1
done
if [[ "$cpu_ok" == true ]] && [[ "$memory_ok" == true ]]; then
echo "System health: OK"
return 0
else
echo "System health: DEGRADED"
return 1
fi
}
check_system_health
When to Use Health Check Pattern
- You’re monitoring system resources
- You need multiple conditions to pass
- You want to check until everything is healthy
- You’re orchestrating startup routines
Important Notes
untilis less commonly used thanwhile, but useful for specific scenarios- The condition is checked before each iteration (condition must be false initially)
- You must ensure the loop condition eventually becomes true, or the loop will run forever
- Always include a way to exit (counter, flag, break, etc.)
- Use
[[ ]]for more readable conditions
Summary
Until loops are the inverse of while loops - they continue until a condition becomes true. While less common than while loops, they’re useful when your condition logic is naturally negative (loop until ready, loop until success, etc.). Master both and choose whichever makes your code clearer and more maintainable.