Skip to main content

How to Loop Until Condition

3 min read
bash

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

TypeContinues WhileSyntaxBest For
whileCondition is truewhile [ cond ]; doPositive conditions
untilCondition is falseuntil [ cond ]; doNegative conditions
forItems remainfor item in list; doIteration over items
Numeric forCounter < limitfor ((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

  • until is less commonly used than while, 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.