A while loop runs its body while a command list succeeds (exit status 0).
That command can be [[ … ]], (( … )), grep -q, read, or anything else that
returns a status—the loop keeps going until that list ends with a non-zero status.
Use while true when you want an open-ended loop and plan to stop with break, a
signal, or an inner condition.
Tested all the commands and code from this article on Ubuntu 25.04, kernel 6.14.0-37-generic, Bash 5.2.37.
For numeric tests, see bash compare numbers.
For the opposite polarity (until), see
bash until vs while loop. For stepping
through lists without read, see bash for loop.
Bash while syntax (while … do … done)
The usual form is one line plus do / done:
while CONDITION_COMMANDS; do
BODY_COMMANDS
doneYou can also put while and do on separate lines; what matters is that the
part between while and do is a normal command list whose last command’s
exit status decides whether another iteration runs.
a=1
while [[ $a -le 3 ]]; do
echo "a=$a"
a=$((a + 1))
doneOutput:
a=1
a=2
a=3Searchers sometimes type while do bash or bash loop while; in the shell the
keyword order is always while …; do … done, not do while.
The loop condition can be any command
Any pipeline or compound command may appear after while. Bash re-runs that list
before each iteration; 0 continues, non-zero stops.
Arithmetic form (handy for counters):
n=0
while ((n < 3)); do
echo "n=$n"
((n++))
doneOutput:
n=0
n=1
n=2Here ((n < 3)) returns 0 while the inequality holds, like a tiny expression
language inside Bash.
Infinite loops (while true)
while true (or while :, since : is a built-in that always succeeds)
loops until something inside the body stops execution—classically break, rarely
return from a function, or an external signal (for interactive loops, you may
also trap SIGINT; see
capture Ctrl+C in bash if you need that).
i=0
while true; do
((++i))
echo "i=$i"
((i >= 3)) && break
doneOutput:
i=1
i=2
i=3Tight spinners (no sleep, no I/O wait) can burn CPU; add a short sleep or
block on a real event when you poll.
break and continue
break leaves the innermost while/until/for/select immediately.
continue skips the rest of the body and jumps to the next test.
k=0
while ((k < 5)); do
((k++))
((k == 2)) && continue
((k == 5)) && break
echo "k=$k"
doneOutput:
k=1
k=3
k=4Iteration 2 is silent because of continue; value 5 exits before the
echo because of break.
break leaves the loop; exit stops the shell
break ends the loop; the script keeps running. exit ends the shell
process—often the whole script—so lines after the loop never run.
bash -c 'f() { while true; do break; done; echo after_loop; }; f; echo still_here'Output:
after_loop
still_herebash -c 'f() { while true; do exit 0; done; echo never; }; f; echo still_here'This second invocation prints nothing from f or the line after it: the
exit terminates the bash -c subshell as soon as it runs.
Reading a file line by line (while read)
While loop in bash over text files almost always uses read, with IFS=
and -r so you do not mangle whitespace or treat backslashes specially.
f=$(mktemp)
printf 'one\ntwo\n' >"$f"
while IFS= read -r line || [[ -n $line ]]; do
echo "read: $line"
done <"$f"
rm -f "$f"Output:
read: one
read: twoThe || [[ -n $line ]] part covers a last line that has no trailing newline.
Do-while style: run the body at least once
Some languages have a do { … } while (condition); form so the body always runs
once before the condition is checked. Bash does not spell that out as its own
keyword, but you can get the same behavior in two straightforward ways.
Option 1: while true and a break
Put the real work first, then decide whether to stop. Here the loop prints n
starting at 0, then stops after n reaches 3:
n=0
while true; do
echo "n=$n"
((n++))
((n >= 3)) && break
doneOutput:
n=0
n=1
n=2The first iteration always runs because the only “condition” on the while line
is the constant true.
Option 2: put read and the test in the while line
The part between while and do is a list of commands; Bash uses the exit
status of the last command as the loop test. This loop reads a name, checks that it
is non-empty, and only then runs the body:
while
read -r name
[[ -n $name ]]
do
echo "hello $name"
done <<'EOF'
alice
bob
EOF
echo doneOutput:
hello alice
hello bob
doneWhat happens each time:
read -r nametakes the next line from the here-document.[[ -n $name ]]succeeds only if that line was not empty.- If both succeed, the
doblock runs (echo). - An empty line makes
[[ -n $name ]]fail, so the loop stops before anotherecho. If the very first line were empty, the body would never run—so this is not the same as “always once.” For a hard guarantee that the body runs before any test, use Option 1.
Nested while loops
Inner loops run to completion for each outer iteration—same scoping rules as other
languages; keep names clear so i / j do not blur together.
o=1
while ((o <= 2)); do
echo "outer $o"
i=1
while ((i <= 2)); do
echo " inner $i"
((i++))
done
((o++))
doneOutput:
outer 1
inner 1
inner 2
outer 2
inner 1
inner 2Summary
A while loop keeps running its body while the command list before do ends
with exit status 0. Use while true (or while :) when you want an open
loop and plan to stop with break, return, or by exiting the process; add
sleep or wait on real I/O when you poll so you do not busy-spin. continue
skips the rest of the current iteration; break leaves only the loop, while
exit ends the shell. For text files, while read with IFS= read -r is
the usual line-by-line pattern. For a do-while effect (body at least once before a
real test), use while true plus a conditional break, or combine read
and [[ … ]] on the while line when that matches how your input arrives.
Further reading:

