Bash break and continue

Tested on RHEL 10.2 (Coughlan)
Package bash 5.2.26-6.el10
Applies to Linux distributions with Bash installed
Privilege Normal user
Scope Bash break and continue in for, while, until, and select, including numeric levels (break 2, continue 2) and how they differ from return and exit. Does not cover loop syntax from scratch or full select menu design.
Related guides Bash shell script tutorial
Shell scripting course hub
Short on time?Beta Get the gist of this 10-minute read in seconds, then ask follow-up questions

Bash break exits a loop early, while continue skips the rest of the current iteration and moves to the next one. Both also accept a numeric level for controlling nested loops.

After break, execution resumes on the first command after done. After continue, Bash starts the next loop iteration and skips whatever was left in the body.


break vs continue — Quick Answer

Both commands apply to the innermost enclosing loop unless you pass a numeric level.

Command What it does Execution resumes
break Exits the loop First line after the matching done
continue Skips the rest of this iteration Next iteration of the same loop
break N Exits N nested loop levels First line after the Nth enclosing done
continue N Skips the rest of the current iteration up through N nesting levels At the next iteration of the Nth enclosing loop

The optional number counts loop nesting levels, not how many iterations to skip. break 2 does not mean "break after two passes"; it means "leave the current loop and the loop that wrapped it."

Syntax for both builtins:

text
break [n]
continue [n]

n is optional and must be 1 or greater. Without it, Bash targets the innermost loop. break 1 is equivalent to break, and continue 1 is equivalent to continue. If n is greater than the number of active enclosing loops, Bash exits or continues as many enclosing loop levels as are available. A non-positive count such as break 0 is an error (break: 0: loop count out of range).


Exit a Loop with break

Use break when you found what you were searching for and later iterations would waste time.

Create two small log files, then stop at the first file that contains ERROR:

bash
printf 'INFO startup\nERROR failed\n' > file1.log && printf 'INFO healthy\n' > file2.log

Run the scan over the fixed list:

bash
for f in file1.log file2.log; do
  echo "checking $f"
  if grep -q 'ERROR' "$f"; then
    echo "match in $f"
    break
  fi
done
output
checking file1.log
match in file1.log

file2.log is never checked because break left the for loop as soon as file1.log matched. Execution continues on the line after done.

The same pattern works when you read a file line by line and stop at a sentinel or first hit. Build search.txt, then read it line by line and stop at the first line whose prefix is found plus a colon:

bash
key=found
colon=:
printf '%s\n' 'no match here' "${key}${colon}alpha" 'tail' > search.txt
while IFS= read -r line; do
  echo "scan: $line"
  if [ "${line#${key}${colon}}" != "$line" ]; then
    echo "first match"
    break
  fi
done < search.txt
output
scan: no match here
scan: found:alpha
first match

The tail line is never scanned because the loop ended at the first matching prefix.

Prefer input redirection (done < file) over piping into while read when loop state matters. A loop on the right side of a pipeline normally runs in a subshell in Bash, so break exits that subshell rather than changing control flow in the parent shell. When the input comes from a command, use process substitution instead:

bash
while IFS= read -r line; do
  ...
done < <(producer)

Replace producer with the command that prints the lines you want to read.


Skip an Iteration with continue

Use continue when one item in the list is invalid or irrelevant but the rest still need processing.

Skip one filename in a fixed list and process the others:

bash
for f in app.log skip.log error.log; do
  if [[ "$f" == skip.log ]]; then
    echo "skip: $f"
    continue
  fi
  echo "process $f"
done
output
process app.log
skip: skip.log
process error.log

continue jumps to the next list item without running echo "process $f" for skip.log. The loop itself keeps going.


Use break and continue in while and until

break and continue work the same in while and until loops; only the loop test differs.

Exit a while loop when a counter reaches a limit. Numeric tests such as (( n < 5 )) use the Bash arithmetic command form:

bash
n=0
while (( n < 5 )); do
  ((n++))
  echo "while n=$n"
  if (( n == 3 )); then
    echo 'break'
    break
  fi
done
echo 'after while'
output
while n=1
while n=2
while n=3
break
after while

n never reaches 4 or 5 because break ran inside the body.

In an until loop, continue skips the remaining commands in the body, then Bash evaluates the until condition for the next iteration:

bash
n=0
until (( n >= 5 )); do
  ((n++))
  echo "until n=$n"
  if (( n == 2 )); then
    echo 'continue'
    continue
  fi
  echo "body n=$n"
done
output
until n=1
body n=1
until n=2
continue
until n=3
body n=3
until n=4
body n=4
until n=5
body n=5

Here n has already been incremented before continue runs. When n is 2, the echo "body n=$n" line never runs, but the next pass still starts with ((n++)) at the top of the body.


Nested Loops with break 2

In nested loops, a plain break only leaves the inner loop. Use break 2 when a condition in the inner loop should end both levels.

If the host-and-port example below used plain break, only the port loop would stop; after inner ($host) would still run and the outer host loop would continue.

Host and port scan: stop entirely when db:80 appears:

bash
for host in web db; do
  for port in 22 80 443; do
    echo "try $host:$port"
    if [[ "$host" == db && "$port" == 80 ]]; then
      echo 'break 2'
      break 2
    fi
  done
  echo "after inner ($host)"
done
echo 'script continues'
output
try web:22
try web:80
try web:443
after inner (web)
try db:22
try db:80
break 2
script continues

break 2 skipped try db:443, skipped after inner (db), and landed on script continues. The outer loop did not start another host.


Nested Loops with continue 2

continue 2 skips the rest of the inner loop and the remainder of the current outer iteration, then starts the outer loop's next item.

Skip every port 80 and move straight to the next host:

bash
for host in web db; do
  for port in 22 80 443; do
    echo "try $host:$port"
    if [[ "$port" == 80 ]]; then
      echo 'continue 2'
      continue 2
    fi
    echo "inner tail $host:$port"
  done
  echo "after inner ($host)"
done
output
try web:22
inner tail web:22
try web:80
continue 2
try db:22
inner tail db:22
try db:80
continue 2

Port 443 never runs for either host. after inner never prints because continue 2 jumped to the next value of host before the inner loop finished.


break in a Bash select Menu

A select loop runs until you break out of it. That is the usual way to close an interactive menu.

bash
select item in Alpha Beta Quit; do
  case "$item" in
    Quit)
      break
      ;;
    *)
      echo "picked $item"
      ;;
  esac
done
echo 'menu closed'

The loop is interactive. A short session might look like this:

text
1) Alpha
2) Beta
3) Quit
#? 1
picked Alpha
#? 3
menu closed

After Quit, break ends the loop and menu closed prints. Without break, select would prompt again.


break vs return vs exit

These commands affect different scopes:

Command Scope Effect
break Innermost loop (or N levels) Leaves loop; caller or script continues
continue Innermost loop (or N levels) Next loop iteration
return Current shell function Exits the function; script continues
exit Entire script or shell Ends the process with an exit status

break does not exit a function or script. return inside a loop leaves the whole function, not just the loop:

bash
function demo_return {
  for i in 1 2 3; do
    if [[ $i -eq 2 ]]; then
      return
    fi
    echo "i=$i"
  done
  echo 'after loop in demo_return'
}

demo_return
echo 'caller continues'
output
i=1
caller continues

At i=2, return ended demo_return before i=3 or after loop in demo_return ran. Use break when you only want to leave the loop inside a function; see Bash functions for how return ends the whole function.


Practical Parsing Example

Real scripts combine continue for bad records and break for a stop sentinel. Create data.txt with mixed lines and an END marker:

bash
printf '%s\n' 'ok:10' 'bad line' 'ok:20' 'skip:30' 'ok:40' 'END' > data.txt

Parse lines that start with ok:, skip anything else, and stop at END. A prefix test with ${line#ok:} checks whether stripping ok: changes the line:

bash
while IFS= read -r line; do
  [[ "$line" == END ]] && break
  if [ "${line#ok:}" != "$line" ]; then
    echo "parsed ${line#ok:}"
  else
    echo "skip: $line"
    continue
  fi
done < data.txt
output
parsed 10
skip: bad line
parsed 20
skip: skip:30
parsed 40

bad line and skip:30 did not start with ok:, so continue moved on. The END line triggered break before any fifth value printed. For larger files, see read a file line by line in Bash for IFS and read details.


Common Mistakes

Symptom Likely cause Fix
Script exits when you wanted to leave one loop Used exit instead of break break stays inside the script; exit ends it
Outer loop keeps running after inner break Forgot nested levels Use break 2 (or higher) to leave multiple loops
break: 0: loop count out of range Used 0 or another invalid level Use a positive integer such as break, break 1, or break 2
break / continue reports it is only meaningful in a loop Command is outside an active loop Use it inside for, while, until, or select; use return for a function or exit for the script
Function ends but you only meant to stop the loop Used return where break fits break for loop only; return for whole function
Code after continue still confuses readers Dead code below continue Put skip logic in if / case; only reachable work below

Deep nesting with many numeric break levels is hard to follow. When a script needs that often, extract the inner loop into a function and use return.


Summary

Bash break stops a loop and hands control to the first command after done. continue skips the rest of the current iteration and starts the next iteration according to that loop's normal control flow. Both accept an optional level: break 2 and continue 2 target outer loops by nesting depth, not by iteration count.

You used break to stop at the first log match and the first found: line, and continue to skip one list item or a malformed record. Nested host-and-port examples showed where execution lands after break 2 versus continue 2. In a select menu, break is the normal way to quit.

The main mix-up is reaching for exit or return when only the loop should change. break and continue affect loops; return leaves a function; exit ends the shell. For line-oriented input, prefer done < file or process substitution over piping into while read, and pair continue for bad lines with break for a sentinel such as END.


References


Frequently Asked Questions

What does break 2 mean?

It exits two nested loop levels at once. Bash counts enclosing loops from the inside out; break 2 leaves the inner loop and the loop that wrapped it, then continues after the outer loop's done.

Can continue target an outer loop?

Yes. continue 2 skips the rest of the inner loop and the remainder of the current outer iteration, then starts the outer loop's next pass. The number is nesting depth, not how many iterations to skip.

Does break exit the script?

No. break only leaves the loop. Commands after done still run. Use exit to end the entire script or shell session.

Can I use break in select?

Yes. break is the standard way to leave a select loop, for example when the user picks Quit. Without break, select keeps prompting.

Finished reading?Beta Get the key takeaways in seconds, then ask follow-up questions
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with 15+ years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)