Bash — The break Built-in

Learn how Bash’s break statement lets you exit for, while, until, and select loops, including nested loops. Explore break n, practical examples, and how break differs from continue, return, and exit.

Bash — The break Built-in

Loops are one of the fundamental building blocks of Bash scripts. They let us process files, iterate over arrays, wait for conditions, and repeatedly execute commands.

But sometimes you don't want a loop to run until its normal condition says “stop.”

You may find what you were looking for, receive a special command from the user, encounter an error, or simply decide that there is nothing more to do.

For those situations, Bash provides the break builtin.

break

It immediately terminates the current loop and execution continues with the command following that loop.

For example:

for number in 1 2 3 4 5; do
    echo "Number: $number"

    if [[ $number -eq 3 ]]; then
        break
    fi
done

echo "Loop finished"

The output is:

Number: 1
Number: 2
Number: 3
Loop finished

The values 4 and 5 are never processed.

Which loops support break?

Bash allows break inside:

  • for
  • while
  • until
  • select

The syntax is:

break [n]

Without an argument, break leaves the innermost enclosing loop.

The optional n is useful with nested loops and specifies how many loop levels should be terminated.

For example:

break 2

leaves the current loop and one enclosing loop.

Using break with for

One of the most common uses is stopping a search once the desired item has been found.

For example:

for number in 1 2 3 4 5 6 7 8 9 10; do
    echo "Checking $number"

    if [[ $number -eq 5 ]]; then
        echo "Found it!"
        break
    fi
done

echo "Search finished"

The loop doesn't need to examine the remaining numbers after 5 has been found.

This pattern is especially useful when the operation inside the loop is expensive:

for server in "${servers[@]}"; do
    if check_server "$server"; then
        echo "Available server: $server"
        break
    fi
done

The loop checks servers until the first successful result.

Searching for a file

Here's another practical example:

for directory in /tmp /var/tmp /opt /usr/local; do
    if [[ -f "$directory/config.txt" ]]; then
        echo "Found configuration in $directory"
        break
    fi
done

Once config.txt has been found, continuing to search the other directories is unnecessary.

This is a good example of why break exists: the loop's normal list of items is still there, but the program has already achieved its goal.

Using break with while

break is particularly convenient with while loops used for interactive input.

while true; do
    read -r -p "Enter something (q to quit): " input

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

    echo "You entered: $input"
done

echo "Goodbye!"

Here:

while true

creates a loop that has no natural stopping condition.

The break provides the exit point when the user enters q.

This is a common Bash pattern:

while true; do
    # do some work

    if [[ some_condition ]]; then
        break
    fi
done

It is particularly useful when the condition that terminates the loop can only be discovered after performing some work.

break with until

The same mechanism works with until:

count=1

until false; do
    echo "Count: $count"

    if [[ $count -eq 5 ]]; then
        break
    fi

    ((count++))
done

Although this example is deliberately simple, the same pattern can be useful when the termination condition is discovered dynamically.

break with select

Bash's select construct is commonly used to create simple interactive menus.

For example:

select choice in Start Stop Quit; do
    case "$choice" in
        Start)
            echo "Starting..."
            ;;
        Stop)
            echo "Stopping..."
            ;;
        Quit)
            echo "Goodbye!"
            break
            ;;
        *)
            echo "Invalid choice"
            ;;
    esac
done

select repeatedly displays the menu until something terminates it.

Here, choosing Quit executes:

break

which ends the select loop.

Notice that case and break have different jobs.

The case statement chooses what to do with the selected value:

case "$choice" in

while break terminates the surrounding loop.

The ;; at the end of a case branch does not terminate the loop.

Nested loops

The default behavior becomes important when loops are nested.

Consider:

for outer in 1 2 3; do
    for inner in a b c; do
        echo "$outer $inner"
        break
    done
done

The result is:

1 a
2 a
3 a

The inner loop stops after its first iteration, but the outer loop continues.

Conceptually:

Outer loop
└── Inner loop
    └── break

break affects the innermost loop containing it.

Breaking out of multiple loops

When nested loops are involved, the optional numeric argument becomes useful.

for outer in 1 2 3; do
    for inner in a b c; do
        echo "$outer $inner"

        if [[ $outer -eq 2 && $inner == b ]]; then
            break 2
        fi
    done
done

echo "All loops finished"

When the script reaches:

2 b

this executes:

break 2

Both loops are terminated, and execution continues with:

echo "All loops finished"

With three nested loops:

for a in ...; do
    for b in ...; do
        while condition; do
            break 3
        done
    done
done

break 3 exits all three enclosing loops.

This can be useful, but large values such as break 3 or break 4 can make control flow difficult to understand. If nested loops become deeply complicated, restructuring the code into functions is often clearer.

break and continue

break and continue are easy to confuse because both affect loop execution.

break ends the loop:

for number in 1 2 3 4 5; do
    if [[ $number -eq 3 ]]; then
        break
    fi

    echo "$number"
done

Output:

1
2

continue, on the other hand, skips the rest of the current iteration and moves to the next one:

for number in 1 2 3 4 5; do
    if [[ $number -eq 3 ]]; then
        continue
    fi

    echo "$number"
done

Output:

1
2
4
5

So the mental model is simple:

break    → stop the loop
continue → skip this iteration

breakreturn, and exit

There are several Bash commands that leave different levels of execution.

Consider this hierarchy:

shell
└── script
    └── function
        └── loop

The commands operate at different levels:

break    → leave the loop
return   → leave the function
exit     → terminate the script/shell

For example:

find_server() {
    for server in "${servers[@]}"; do
        if check_server "$server"; then
            echo "Found: $server"
            break
        fi
    done

    echo "Search complete"
}

Here, break leaves the for loop, but the function continues:

echo "Search complete"

If you wanted to leave the function immediately instead, you would use return:

find_server() {
    for server in "${servers[@]}"; do
        if check_server "$server"; then
            echo "Found: $server"
            return 0
        fi
    done

    return 1
}

And exit would terminate the script itself:

exit 0

Choosing the right command is important because each one affects a different level of control flow.

A practical command loop

A useful real-world pattern combines whilecase, and break.

while true; do
    read -r -p "server> " command

    case "$command" in
        start)
            echo "Starting server..."
            ;;
        stop)
            echo "Stopping server..."
            ;;
        status)
            echo "Server is running."
            ;;
        quit|exit)
            echo "Leaving..."
            break
            ;;
        *)
            echo "Unknown command: $command"
            ;;
    esac
done

The loop continues processing commands until the user enters either:

quit

or:

exit

At that point:

break

returns execution to the command following the while loop.

This structure is useful for simple command-line interfaces, menus, interactive utilities, and administration scripts.

Multiple termination conditions

A loop may have more than one reason to stop.

For example:

while true; do
    read -r input

    if [[ $input == quit ]]; then
        break
    fi

    if [[ $input == error ]]; then
        echo "Stopping because an error was received."
        break
    fi

    process "$input"
done

The loop has two possible termination paths.

You can also use break when a command fails:

while true; do
    if ! process_item; then
        echo "Processing failed."
        break
    fi
done

This can be much clearer than trying to encode every possible condition into the while expression itself.

When not to use break

break is useful, but it shouldn't become a substitute for designing a clear loop condition.

For example, this:

while [[ $count -lt 10 ]]; do
    echo "$count"
    ((count++))
done

already clearly describes when the loop ends.

There is no need to turn it into:

while true; do
    echo "$count"
    ((count++))

    if [[ $count -ge 10 ]]; then
        break
    fi
done

Both work, but the first version expresses the loop's purpose directly.

break becomes particularly useful when the termination condition is discovered inside the loop or when there are several independent ways to stop.

A common mistake: using break outside a loop

break needs an enclosing loop.

This is invalid:

#!/usr/bin/env bash

echo "Hello"
break

Bash reports an error similar to:

bash: break: only meaningful in a `for', `while', or `until' loop

If you are not inside a loop, break is not the appropriate way to leave the current execution context.

Use return inside a function or exit when you actually want to terminate the script.

Checking the exit status

A successful break normally returns status 0.

For example:

while true; do
    break
done

echo "$?"

prints:

0

You generally won't need to test the status of break itself, but this becomes relevant when writing scripts that carefully track command failures and return codes.

Keep nested control flow readable

break 2 is useful, but don't forget that someone else may eventually have to understand your code.

Compare:

for server in "${servers[@]}"; do
    for port in "${ports[@]}"; do
        if check_port "$server" "$port"; then
            echo "Found: $server:$port"
            break 2
        fi
    done
done

with a more structured approach using a function and a return value.

The first version is perfectly valid, but break 2 requires the reader to know exactly how many loops surround it.

A little control flow is helpful.

A control-flow escape plan worthy of a space shuttle is probably a sign that the function needs splitting.

Bash documentation

break is a Bash builtin, so you can read its documentation directly from Bash:

help break

You can also inspect the related commands:

help continue
help return
help exit

This is often the quickest way to check the exact syntax available in the Bash version you're using.

Quick reference

The basic command:

break

leaves the current loop.

With nested loops:

break 2

leaves two loop levels.

And:

break 3

leaves three.

Typical usage:

for item in "${items[@]}"; do
    if [[ condition ]]; then
        break
    fi
done

Interactive loop:

while true; do
    read -r input

    [[ $input == quit ]] && break

    process "$input"
done

Nested loops:

for a in ...; do
    for b in ...; do
        break 2
    done
done

Remember the distinction:

break    → leave the loop
continue → skip the current iteration
return   → leave the function
exit     → terminate the script/shell

Conclusion

The break builtin provides a simple way to stop a Bash loop when its normal termination condition is no longer the right one.

Its most common uses are straightforward:

  • stop searching after finding the desired result;
  • terminate an interactive loop when the user requests it;
  • stop processing after an error;
  • leave nested loops with break 2break 3, and so on;
  • exit a select menu.

The basic form is:

break

and for nested loops:

break 2

Use it where it makes the control flow clearer. If a loop has one obvious termination condition, put that condition directly into whileuntil, or the loop structure itself. When the decision to stop emerges during processing, break is often exactly the right tool.

Sometimes a loop simply needs to know when enough is enough.

That's break.

Read next

Bash — The alias Built-in

Bash aliases let you turn long, frequently used commands into short, memorable shortcuts. Learn how alias works, how to create, inspect, remove, and persist aliases, and when a function or script is a better choice.

Bash — The eval Built-in

> **Learn what Bash’s `eval` really does, why it performs a second round of shell parsing, how it enables dynamic commands and variables, and why that same power can create serious security risks. Explore safer alternatives such as arrays, functions, and indirect expansion.**

Bash — The echo Built-in

Explore Bash’s echo built-in: print text and variables, control newlines, use escape sequences, handle quoting and special characters, and avoid common pitfalls. Plus, learn when printf is a better choice for precise and predictable output.