A while loop in Bash runs while the while test command succeeds. Pair it with sleep to pace iterations, compare the clock against a single end time when you need “run for five minutes”, or wrap commands in GNU timeout when something must not run past a hard wall. The snippets below fit a typical shell script.
Tested on Ubuntu 25.04, kernel 6.14.0-37-generic, Bash 5.2.37, GNU coreutils
dateandtimeout(2026-06-14).
While command bash (while / until)
The general form is:
while CONDITION; do
# body
doneCONDITION is any command; exit status 0 means true. The opposite is until. That is the core of while / until usage inside a shell script.
While loop in bash shell until a deadline (date + sleep)
Pick a runtime string GNU date -d understands, convert the stop instant to Unix seconds once, then compare date -u +%s in the loop. This avoids drifting from summing sleep durations in long runs.
#!/usr/bin/env bash
runtime="2 minutes" # change as needed
end_epoch=$(date -ud "now + $runtime" +%s)
while [[ $(date -u +%s) -le $end_epoch ]]; do
echo "Time now: $(date +%H:%M:%S)"
sleep 10 # interval between iterations
doneUsing date -ud "now + $runtime" is clearer than relying on date -ud "$runtime" alone, which can be ambiguous across locales.
On Bash 5+ you can avoid spawning date every iteration:
end=$((EPOCHSECONDS + 120)) # 120 seconds from now
while (( EPOCHSECONDS <= end )); do
echo "Time now: $(date +%H:%M:%S)"
sleep 10
donesleep accepts suffixes such as 10s, 1m, 0.5s on GNU coreutils—handy for pacing loops.
bash while loop timeout: counter + break
Another timeout pattern is a while true body, a running total, and break when the budget is used:
#!/usr/bin/env bash
max_seconds=30
elapsed=0
step=5
while true; do
echo "Time now: $(date +%H:%M:%S) (elapsed ${elapsed}s)"
sleep "$step"
elapsed=$((elapsed + step))
if (( elapsed >= max_seconds )); then
echo "Stopping after ${max_seconds}s."
break
fi
doneThis matches the old “add 10 until 300” idea, but keeps names readable. Drift is still dominated by how long the work between sleeps takes.
bash timeout while loop: GNU timeout and exit 124
For “run this command but not longer than N seconds”, wrap the work in timeout from GNU coreutils. It sends SIGTERM (then SIGKILL if needed) and exits with status 124 when the cap hits.
Background jobs with per-job limits:
#!/usr/bin/env bash
echo "$(date +%H:%M:%S): start"
pids=()
timeout 2 bash -c 'sleep 20; echo job1' &
pids+=($!)
timeout 3 bash -c 'sleep 1; echo job2' &
pids+=($!)
for pid in "${pids[@]}"; do
wait "$pid"
st=$?
if [[ $st -eq 124 ]]; then
echo "$(date +%H:%M:%S): pid $pid stopped by timeout (exit 124)"
else
echo "$(date +%H:%M:%S): pid $pid finished (exit $st)"
fi
doneExample output (timestamps will differ):
17:47:41: start
job2
17:47:44: pid 68070 stopped by timeout (exit 124)
17:47:44: pid 68071 finished (exit 0)See man timeout for --kill-after, --signal, and foreground use without &.
Related topics
Summary
while / until control flow is a test command plus sleep for pacing. To run until a clock time, compute one end epoch with date or use EPOCHSECONDS on Bash 5+ instead of calling date in a tight loop. For a timeout implemented in pure shell, accumulate elapsed time and break. When you need the kernel to enforce a cap on an external command, use GNU timeout and treat exit 124 as “hit the wall.”
Further reading: pause shell script, Bash wait with timeout, timeout(1).

