VMware ESXi and vSphere Cluster Management

Linux Shell while Loops

Learn how to write Linux shell while loops, test conditions, update counters, prevent infinite loops, and choose between while, until, and for.

A while loop is a shell control structure for running the same command block repeatedly while a condition succeeds. The shell evaluates the condition before every iteration. If the test succeeds, the loop body runs; when the test becomes false, execution stops and continues after done.

While loops are useful when repetition depends on a changing condition, such as waiting for a file, reading input until the end of a stream, or counting until a limit is reached.

Basic while Loop Syntax

A multiline shell while loop has this structure:

while [ condition ]
do
  commands
 done

The usual formatting does not include an extra space before done; the complete form is:

while [ condition ]
do
  commands
done

while begins the loop. The condition is a command or test whose exit status determines whether the body runs. do begins the repeated command block, and done closes it.

ComponentRoleExample
whileStarts a loop that continues while its test succeeds.while
Condition or testDetermines whether another iteration is allowed.[ "$NUM" -lt 5 ]
doBegins the loop body.do
Loop body commandsCommands repeated on each successful test.echo "$NUM"
doneEnds the loop body.done

In an interactive shell, semicolons can separate parts of a loop on one line:

while [ "$NUM" -lt 5 ]; do echo "$NUM"; let NUM=NUM+1; done

In a script, the multiline form is usually easier to read.

Conditions and the test Command

The syntax [ ... ] is the shell's test command written in a bracket form. It evaluates a comparison or another condition and returns an exit status. An exit status is the numeric result returned by a command. In shell scripting, status zero generally means success, while a nonzero status means failure.

A while loop runs its body when the condition command returns status zero. For example:

while [ "$NUM" -lt 5 ]
do
  echo "$NUM"
done

Here, the test succeeds when NUM is numerically less than five. The body runs only after a successful test. Once the test fails, the shell skips the body and moves past done.

Spaces are required around the opening and closing brackets and between the test operands. The brackets are command arguments, not punctuation that can be attached to other text. This is valid:

[ "$NUM" -lt 5 ]

This is invalid because the required spaces are missing:

[$NUM -lt 5]

Numeric Test Operators

Numeric comparison operators compare integer values. Do not use the string comparison operators when you intend to compare numbers.

OperatorMeaningExample condition
-ltNumerically less than[ "$NUM" -lt 5 ]
-leNumerically less than or equal to[ "$NUM" -le 5 ]
-eqNumerically equal to[ "$NUM" -eq 5 ]
-neNumerically not equal to[ "$NUM" -ne 5 ]
-gtNumerically greater than[ "$NUM" -gt 5 ]
-geNumerically greater than or equal to[ "$NUM" -ge 5 ]

Variables in Loop Conditions

Initialize a loop variable before entering a count-controlled loop. Shell assignment has no spaces around the equals sign:

NUM=0

When reading the variable's value, use the dollar sign for variable expansion. Expansion replaces a reference such as $NUM with its current value:

echo "$NUM"
[ "$NUM" -lt 5 ]

These two forms have different purposes:

  • NUM=0 assigns a value to the variable.
  • $NUM expands the variable to its current value.
  • "$NUM" expands it while preserving it as one argument, including when the value is empty or contains whitespace.

A count-controlled loop must change the controlling variable inside the body. If NUM remains zero, a condition such as [ "$NUM" -lt 5 ] remains true forever.

Arithmetic Updates

The loop needs an arithmetic update on every iteration so that the condition can eventually become false. The following example uses let, an arithmetic builtin supported by Bash and Korn shell:

NUM=0
while [ "$NUM" -lt 5 ]
do
  echo "The number is $NUM."
  let NUM=NUM+1
done

Modern Bash and Korn shell code commonly uses arithmetic syntax instead:

count=0
while [ "$count" -lt 3 ]
do
  printf 'Pass %s\n' "$count"
  ((count++))
done

((count++)) increments the numeric variable after the command is evaluated. Another form uses arithmetic expansion and assignment:

NUM=$((NUM + 1))

Arithmetic expansion is suitable for many POSIX-style shell scripts. The let and (( ... )) forms are shell-specific arithmetic features, so execute them with a compatible interpreter such as Bash when required.

Reading a Counting Loop

Consider this complete loop:

NUM=0
while [ "$NUM" -lt 5 ]
do
  echo "The number is $NUM."
  let NUM=NUM+1
done

Its sequence is:

  1. Set NUM to zero.
  2. Test whether NUM is less than five.
  3. Print the current value.
  4. Increase NUM by one.
  5. Return to the condition test.

The output values are 0, 1, 2, 3, and 4. A less-than test with an upper bound of five excludes five itself. After printing four, the increment changes NUM to five. The next test, [ 5 -lt 5 ], fails, so the body does not run again.

Condition-Driven Example: Wait for a File

A while loop does not have to count. It can repeatedly check external state:

while [ ! -f /tmp/ready.flag ]
do
  echo "Waiting for ready.flag"
  sleep 1
done
echo "File detected"

The -f test succeeds when the path is a regular file. The exclamation mark negates the test, so the loop continues while the file does not exist. Once /tmp/ready.flag appears, the condition becomes false and the script prints File detected.

Loop Safety and Termination

An infinite loop is a loop that does not terminate because its continuation condition never becomes false. Before running a loop, identify what can make its condition fail.

  • For a counter loop, verify that every iteration changes the counter toward the limit.
  • For a file or process check, verify that the external state can eventually change.
  • Use a small bound while testing.
  • Print diagnostic values temporarily so you can observe the condition-dependent state.
  • Use a delay such as sleep 1 when polling external state, rather than checking continuously.

If an accidentally endless foreground script is running, press Ctrl+C to send an interrupt and stop it.

Running a Shell Script

Save a loop in a script file and run it with an interpreter that supports its syntax. For Bash-compatible code:

bash script.sh

Using the intended interpreter matters. Arithmetic syntax may work in Bash but fail when the script is executed by a different shell. If portability is important, choose syntax supported by the target shell and test the script in that environment.

while, until, and for Loops

Shell loop constructs differ mainly in how they decide whether another iteration should run.

Loop typeRuns whenBest use case
whileThe test succeeds.A condition remains true, such as a file not yet existing or a counter being below a limit.
untilThe test fails.Repeat work until a condition succeeds.
forThere is another item in a list, range, or other sequence.Iterate through a known collection or fixed set of values.

Choose a while loop when the stopping decision depends on a condition that is checked before each iteration. A for loop is often clearer when the items or number of iterations are already known. An until loop can make code more readable when the natural description is “keep going until this test succeeds.”

Troubleshooting while Loops

Syntax error near [ or do

A common cause is missing spaces in the test, such as [$NUM -lt 5], or a missing separator before do in a one-line loop. Use the canonical multiline structure or separate one-line components with semicolons:

while [ "$NUM" -lt 5 ]; do
  echo "$NUM"
  NUM=$((NUM + 1))
done

The loop never stops

The counter may not be incremented, the update may affect a different variable, or the condition may be impossible to make false. Display the controlling value in the loop and confirm that it moves toward the boundary. Stop a running foreground loop with Ctrl+C.

Integer-expression error

The variable may be empty or contain nonnumeric text. Initialize it to a valid integer and quote its expansion in the test:

NUM=0
while [ "$NUM" -lt 5 ]

One extra or one fewer iteration

Trace the initial value, condition, body, and update in that order. Use -lt for an exclusive upper bound, so values below five are selected. Use -le when the boundary value itself should be included. Also check whether the counter is updated before output instead of after output.

Arithmetic syntax differs between shells

Some arithmetic forms are Bash or Korn shell features. Run Bash-compatible code with bash script.sh, or use arithmetic expansion when the target shell supports it and portability is required.