Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

An infinite while loop in Bash runs while its condition returns exit status 0. The clearest form is:

while true; do
    command
    sleep 1
done

The traditional equivalent is while :. Both work because true and the Bash null command : always return success. Use an explicit exit path such as break, a signal trap, or a controlled condition when the loop should eventually stop.

How a Bash while loop becomes infinite

The general syntax is:

while condition
do
    commands
done

Bash runs the commands while the condition command or compound command returns status 0. A nonzero status ends the loop. Therefore, a condition that always succeeds creates an intentional infinite loop:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
while true; do
    # Work performed repeatedly
 done

When do is on the same line as the condition, separate it with a semicolon:

while true; do
    printf '%sn' "Running"
done

With multiline formatting, the semicolon is unnecessary.

What : means

: is Bash’s null command, also called the no-op command. It performs no operation and returns success:

:
printf 'status: %sn' "$?"   # status: 0

Thus, this loop means “run while the null command succeeds”:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
while :; do
    printf '%sn' "Still running"
    sleep 1
done

It is not a special forever keyword. It is simply a command whose successful status keeps the while condition true. The form is a traditional shell idiom, while while true is often easier for beginners and maintenance programmers to understand.

while : versus while true

Form Best use Notes
while true Clear, self-documenting scripts Usually the easiest form to recognize
while : Traditional shell code Uses the shell’s null command
while (( 1 )) Bash arithmetic syntax Valid, but less idiomatic here
while [ 1 ] Technically valid shell code Obscure; avoid it for readability

There is no meaningful practical performance reason to choose one over the other for normal scripts. Choose the form that communicates intent to the people who will read the code.

Why while false does not loop

false returns a nonzero status, so the body is skipped immediately:

while false; do
    printf '%sn' "This never runs"
done

The three basic statuses are easy to demonstrate:

true
printf 'true status: %sn' "$?"   # 0

:
printf 'colon status: %sn' "$?"  # 0

false
printf 'false status: %sn' "$?"  # 1

Runnable example

Create a script with a deliberate one-second delay:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
cat > infinite-loop.sh <<'EOF'
#!/usr/bin/env bash

while true; do
    printf '%sn' 'Still running; press Ctrl+C to stop.'
    sleep 1
done
EOF

chmod +x infinite-loop.sh
./infinite-loop.sh

Press Ctrl+C to normally send SIGINT to the foreground process group. This is convenient for testing, but a long-running script should usually also provide an intentional shutdown path.

Ways to stop an infinite loop

Use break

break exits the innermost enclosing loop and lets the rest of the script continue:

#!/usr/bin/env bash

while true; do
    read -r -p 'Enter q to quit: ' answer

    if [[ $answer == q ]]; then
        break
    fi

    printf 'You entered: %sn' "$answer"
done

printf '%sn' 'Loop ended'

In nested loops, break 2 exits two loop levels.

Use exit

Use exit when the entire script must terminate, not merely the loop:

while true; do
    if some_fatal_condition; then
        printf '%sn' 'Fatal error' >&2
        exit 1
    fi
	do_work
done

Use a shutdown flag

A flag makes the loop’s termination state explicit:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
running=1

while (( running )); do
    if should_stop; then
        running=0
    else
        do_work
    fi
done

cleanup

Handle termination signals

For a worker or polling script, trap INT and TERM and perform cleanup after the loop:

#!/usr/bin/env bash

stop_requested=0

on_signal() {
    stop_requested=1
}

trap on_signal INT TERM

while (( ! stop_requested )); do
    do_work
    sleep 1
done

cleanup
printf '%sn' 'Shutting down cleanly'

A simple trap is suitable for introductory scripts. If the loop starts background jobs or external processes, shutdown may also need to wait for or terminate those child processes. Ctrl+C is not a universal cleanup strategy: signals can be trapped, ignored, delivered to wrappers, or behave differently for background jobs.

Read input safely in an infinite loop

For interactive commands, check the status of read so end-of-file does not leave the script waiting or processing an invalid value:

while true; do
    if ! IFS= read -r -p 'Command: ' command; then
        printf '%sn' 'End of input'
        break
    fi

    case $command in
        quit|exit)
            break
            ;;
        *)
            printf 'Unknown command: %sn' "$command"
            ;;
    esac
done

IFS= preserves leading and trailing whitespace, and -r prevents read from treating backslashes as escape characters. In Bash, [[ ... ]] is generally preferable for string tests because it avoids several word-splitting and quoting pitfalls.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Menu-driven example

#!/usr/bin/env bash

while true; do
    printf 'n'
    printf '%sn' 
        '1) Show date' 
        '2) Show current directory' 
        '3) Quit'

    if ! read -r -p 'Choose an option: ' choice; then
        printf '%sn' 'End of input'
        break
    fi

    case $choice in
        1)
            date
            ;;
        2)
            pwd
            ;;
        3)
            printf '%sn' 'Goodbye.'
            break
            ;;
        *)
            printf '%sn' 'Invalid choice.' >&2
            ;;
    esac
done

Prevent a busy loop

This loop may consume substantial CPU if check_status returns immediately:

while true; do
    check_status
done

Add a delay when polling:

while true; do
    check_status
    sleep 5
done

Subsecond polling is possible, but it should be deliberate:

while true; do
    check_status
    sleep 0.2
done

A delay is not required when the loop blocks naturally on input, a socket, or another event source. The important rule is that a loop must either do useful blocking work or rate-limit repeated checks. Also avoid printing on every fast iteration, since redirected output can rapidly fill a terminal, log, or disk.

Prefer a condition when termination is known

An explicit condition makes a termination guarantee visible. For bounded retries:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
attempt=1
max_attempts=5

while (( attempt <= max_attempts )); do
    if command_succeeds; then
        break
    fi

    (( attempt++ ))
    sleep 2
done

Use until when the natural meaning is “keep trying until this command succeeds”:

until check_ready; do
    printf '%sn' 'Not ready; retrying...'
    sleep 1
done

Do not use an unbounded loop for a retry policy that should have a timeout, maximum attempt count, or failure condition.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Common mistakes

Forgetting to update loop state

n=1

while (( n < 10 )); do
    echo "$n"
    # Missing: (( n++ ))
done

The condition never changes, so this is an accidental infinite loop. Add the state update:

(( n++ ))

Confusing a blocking read with a hang

In this loop, the script waits for input at read:

while true; do
    read -r value
    [[ $value == quit ]] && break
done

That behavior is expected. Handle EOF explicitly if the script may receive redirected or piped input.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Starting unbounded background work

while true; do
    do_work &
    sleep 1
done

The ampersand starts asynchronous work. If each job takes longer than a second, processes can accumulate without limit. Use wait, a concurrency limit, or a worker design that applies backpressure.

Assuming set -e solves loop termination

set -e is not a timeout or universal loop-safety mechanism. Bash’s errexit behavior depends on context, and it does not replace an explicit exit condition, signal policy, or resource limit.

Pipeline subshell behavior

Variables assigned inside a piped loop may not be available afterward because the loop can execute in a subshell:

printf '%sn' a b c | while read -r item; do
    last=$item
done

printf '%sn' "$last"

When you need the loop’s variable afterward, process substitution is often appropriate in Bash:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
while IFS= read -r item; do
    last=$item
done < <(printf '%sn' a b c)

printf '%sn' "$last"

Bash and POSIX portability

while : is portable shell syntax, and while true is widely supported by Unix shells. The following features in this article are Bash-specific or Bash-oriented: [[ ... ]], (( ... )), process substitution, and the #!/usr/bin/env bash interpreter line.

For Bash grammar and builtins, see the Bash Reference Manual. For portable shell rules, consult the POSIX Shell Command Language specification.

When an infinite loop is the right tool

Infinite loops are not inherently bad. They are appropriate for interactive menus, workers, polling processes, and long-running consumers when the script has a controlled shutdown method, sensible resource use, and clear error handling.

For a real production service, consider whether a service manager such as systemd should own restarting, logging, dependencies, timeouts, and signal behavior instead of placing all those responsibilities in a shell loop.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Quick reference

# Explicit infinite loop
while true; do
    work
 done

# Traditional shell idiom
while :; do
    work
 done

# Stop the current loop
break

# Stop the entire script
exit 1

# Bounded loop
while (( attempts < max_attempts )); do
    work
    (( attempts++ ))
done

# Wait until a command succeeds
until check_ready; do
    sleep 1
done

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.