Linux Shell until Loop
Learn how to use the Linux shell until loop to repeat commands while a condition is false, with syntax, counters, polling, retries, and troubleshooting.
An until loop is a shell control-flow construct that repeatedly runs a loop body until a condition succeeds. It is useful when the stopping state is easier to describe than the state that should continue.
Shell flow control uses command exit statuses. An exit status of 0 means success, while a nonzero status means failure. An until loop runs its body when the condition command returns nonzero, conventionally treated as false. It stops when that command returns 0.
If you are new to shell variables, command execution, or exit statuses, review the Bourne Again Shell (Bash) basics first.
Basic until-loop syntax
The usual multiline form is:
until condition_command
do
commands
done
condition_command is any command whose exit status determines whether another iteration occurs. The commands between do and done are the loop body.
In a one-line form, a semicolon separates the condition from do:
until condition_command; do commands; done
The condition is evaluated before every potential iteration, including the first one. If it succeeds on the first test, the body runs zero times.
Execution flow
- Initialize variables or other state before the loop.
- Run the condition command.
- If the command returns nonzero, execute the loop body.
- Update the variable or external state that the condition examines.
- Return to the condition and test again.
An initially true condition causes zero iterations. An initially false condition causes at least one iteration, unless the body changes the state and the condition succeeds on the next test.
Numeric counter example
This example starts a counter at zero, displays it, increments it, and stops when it reaches five:
num=0
until [ "$num" -eq 5 ]
do
echo "The number is $num"
num=$((num + 1))
done
The bracket expression is tested before each iteration. The output contains values from 0 through 4. When num becomes 5, [ "$num" -eq 5 ] returns status 0, so the loop ends.
The increment is essential. Without num=$((num + 1)), the value would remain zero and the loop would be an infinite loop.
Conditions and exit statuses
[ ... ] is the shell test command. It is also commonly called a bracket expression. Spaces are required after [ and before ]:
[ "$num" -eq 5 ]
The command test "$num" -eq 5 expresses the same test. The brackets are command syntax, so they are not punctuation that can be attached to the operands.
Use numeric operators for numbers and string operators for text:
Quote variable expansions in string tests when values may be empty or contain spaces:
until [ "$status" = "ready" ]
do
status="$(get-status)"
done
An until condition does not have to use [ ... ]. Any command can serve as the condition because shell flow control uses the command's exit status. A successful command ends the loop; a failing command allows another iteration.
until versus while
A while loop repeats while its condition succeeds. An until loop repeats while its condition fails.
These forms express the same continuation rule:
until [ "$num" -eq 5 ]
do
echo "The number is $num"
num=$((num + 1))
done
while [ "$num" -ne 5 ]
do
echo "The number is $num"
num=$((num + 1))
done
Choose until when the terminating state is clearer, such as “until the file exists” or “until the service is ready.” Choose while when the continuing state is clearer, such as “while the input is valid.”
Example: wait until a file exists
The -e test succeeds when the specified path exists. This loop prints a message while the file is absent and checks again after one second:
until [ -e "/tmp/ready.flag" ]
do
echo "Waiting for the file..."
sleep 1
done
echo "File found."
The sleep command prevents the loop from checking continuously and using unnecessary CPU. In a real script, make sure the file path is correct and consider adding a timeout or maximum number of checks.
Example: retry a command until it succeeds
Because any command can be a condition, a command that may temporarily fail can be retried directly:
until curl -fsS https://example.com/health >/dev/null
do
echo "Service is not ready; retrying..."
sleep 5
done
echo "Service is ready."
Here, curl returns success when the health request succeeds. Until then, the loop waits five seconds and tries again. The options -f, -s, and -S make HTTP failures affect the exit status while keeping output manageable.
For production scripts, add a retry limit or deadline. A service could remain unavailable indefinitely, and an unbounded retry loop would never finish.
Safe loop construction
- Initialize state: assign counters, status variables, paths, and other inputs before the first test.
- Change tested state: the body must update the variable or external resource that can make the condition succeed.
- Use the correct comparison: use
-eq,-lt, or another numeric operator for numbers; use=or!=for strings. - Quote expansions: write string tests such as
[ "$value" = "expected" ]when a value may be empty or contain whitespace. - Delay polling: use
sleepwhen repeatedly checking files, services, or other external state. - Bound long operations: use a retry counter, a deadline, or a timeout where the desired state might never occur.
- Provide interruption: a foreground shell loop can normally be interrupted with
Ctrl+C.
Troubleshooting until loops
The loop never ends
- The body may not update the variable or resource tested by the condition.
- The target condition may be impossible to reach.
- A command used as the condition may continue returning failure.
Print diagnostic values during development, verify that the body changes the relevant state, and add a retry counter or timeout for external services.
The test reports a syntax error or behaves unexpectedly
- Check for spaces after
[and before]. - Use numeric operators such as
-eqinstead of string operators for numbers. - Quote expansions that may be empty or contain spaces.
The loop does not run at all
The condition was already successful before the first test. Check the initial variable values and the initial file or command state. If at least one execution is required, choose an initial state that makes the first condition fail, or use a different loop structure.
A polling loop consumes too many resources
The condition is probably being tested continuously without a pause. Add sleep between attempts and choose a delay appropriate to how quickly the resource is expected to become available.
Exam-relevant points
- An
untilloop executes its body while its condition command returns nonzero. - The loop stops when the condition command returns zero.
- The condition is checked before every iteration, so an initially successful condition produces zero iterations.
[ ... ]is a command and requires spaces around its contents.- Use
-eqfor numeric equality and=for string equality. - A loop that never changes the tested state can become infinite.
- Any command can be used as the condition because its exit status controls shell flow.
Related shell topics
After learning until, continue with while loops, for loops, if statements, case statements, and break and continue. The Linux command-line topic index provides related shell and system administration lessons.