Skip to main content

How to Skip Loop Iteration in Bash

• 3 min read
bash loops control flow continue

Quick Answer: Skip to the Next Loop Iteration

Use the continue statement to skip the rest of the current iteration and jump immediately to the next one. It keeps the loop running but skips any code after the continue statement in that iteration—essential for filtering out unwanted items.

Quick Comparison: Loop Control Statements

MethodEffectUse CaseWhen to Use
continueSkip to next iterationFilter out invalid itemsMost common—skip one iteration
continue NSkip N loop levelsNested loop filteringMulti-level iteration control
breakExit loop completelyStop processing entirelyWhen you’re done, not filtering
returnExit functionStop everything in functionWhen conditions require full exit

Bottom line: Use continue for filtering (skip iteration), break for stopping completely, and combine them to handle complex loop logic.


Skip iterations using the continue statement. The continue command allows you to jump to the next iteration of a loop, skipping remaining commands in the current iteration. This is essential for filtering and conditional processing.

Method 1: Basic Continue in For Loops

Use continue to skip to the next iteration when a condition is met. The loop keeps running but jumps over the remaining code in that iteration.

When to Use Basic Continue

  • Skip items matching a pattern or condition
  • Exclude unwanted values from processing
  • Filter data during iteration without breaking loop
  • Process only items passing validation
# Skip specific iteration
for i in {1..5}; do
  if [ $i -eq 3 ]; then
    continue  # Skip iteration when i=3
  fi
  echo "$i"
done

# Output:
# 1
# 2
# 4
# 5

Example with practical filtering:

# Process only valid items
for item in apple banana cherry; do
  if [ "$item" = "banana" ]; then
    continue  # Skip banana
  fi
  echo "Fruit: $item"
done

# Output:
# Fruit: apple
# Fruit: cherry

Method 2: Continue in While Loops

While loops benefit from continue when processing conditional data streams or reading files line-by-line with multiple filtering conditions.

When to Use Continue in While Loops

  • Skip empty or invalid lines in file processing
  • Filter configuration files (skip comments, blanks)
  • Process data streams with selective conditions
  • Reading user input with validation
count=0

while [ $count -lt 5 ]; do
  ((count++))

  if [ $((count % 2)) -eq 0 ]; then
    continue  # Skip even numbers
  fi

  echo "Odd: $count"
done

# Output:
# Odd: 1
# Odd: 3
# Odd: 5

More complex example:

# Process with filtering
while IFS= read -r line; do
  # Skip empty lines
  [ -z "$line" ] && continue

  # Skip lines that start with #
  [[ "$line" =~ ^# ]] && continue

  # Process valid line
  echo "Valid: $line"
done < config.txt

Method 3: Skip Empty Lines and Comments

One of the most practical uses of continue—cleaning data as you process it. Skip empty lines, comments, and invalid entries to process only valid data.

When to Use for Filtering

  • Processing configuration files with comments
  • Reading user-generated data with formatting issues
  • Filtering log files to skip noise
  • Validating CSV files during import
# Read file, skip empty lines
while IFS= read -r line; do
  [ -z "$line" ] && continue  # Skip empty line
  echo "Line: $line"
done < input.txt

# Or using grep to show only non-empty:
grep -v '^$' input.txt | while read -r line; do
  echo "Line: $line"
done

Method 4: Multi-Condition Filtering

Combine multiple continue statements to skip multiple types of invalid data in a single loop.

# Skip comment lines
while IFS= read -r line; do
  [[ "$line" =~ ^#.* ]] && continue      # Skip lines starting with #
  [ -z "$line" ] && continue              # Skip empty lines
  echo "Processing: $line"
done < config.txt

Example with real config:

# Input (settings.conf):
# Database Configuration
DB_HOST=localhost
# DB_PORT is obsolete
DB_NAME=mydb

# Processing with continue:
while IFS='=' read -r key value; do
  [[ "$key" =~ ^# ]] && continue  # Skip comments
  [ -z "$key" ] && continue        # Skip empty lines
  echo "Config: $key = $value"
done < settings.conf

# Output:
# Config: DB_HOST = localhost
# Config: DB_NAME = mydb

Method 5: Continue in Nested Loops

When in nested loops, continue only affects the innermost loop by default. Use continue N to skip multiple nesting levels.

for i in {1..3}; do
  echo "Outer: $i"
  for j in {1..3}; do
    if [ $j -eq 2 ]; then
      continue  # Continue INNER loop only
    fi
    echo "  Inner: $j"
  done
done

# Output:
# Outer: 1
#   Inner: 1
#   Inner: 3
# Outer: 2
#   Inner: 1
#   Inner: 3
# Outer: 3
#   Inner: 1
#   Inner: 3

Method 6: Continue Multiple Nesting Levels

Use continue N to skip to the next iteration of the Nth outer loop, bypassing inner loop iterations entirely.

# Continue outer loop (skip remaining inner iterations)
for i in {1..3}; do
  for j in {1..3}; do
    if [ $j -eq 2 ]; then
      continue 2  # Skip to next i iteration
    fi
    echo "i=$i, j=$j"
  done
done

# Output:
# i=1, j=1
# i=2, j=1
# i=3, j=1

More complex nested example:

for i in {1..2}; do
  for j in {1..2}; do
    for k in {1..2}; do
      if [ $k -eq 2 ]; then
        continue 2  # Skip to next j iteration
      fi
      echo "i=$i, j=$j, k=$k"
    done
  done
done

# Only processes k=1 for each j

Practical Examples

Example 1: Process Valid Files Only

#!/bin/bash

directory="${1:-.}"

for file in "$directory"/*; do
  [ -f "$file" ] || continue      # Skip non-files (directories, etc.)
  [ -r "$file" ] || continue      # Skip non-readable files
  [ -s "$file" ] || continue      # Skip empty files

  # Now process file
  lines=$(wc -l < "$file")
  echo "$file: $lines lines"
done

Output:

./script.sh: 42 lines
./data.txt: 100 lines
./notes.md: 25 lines

Example 2: Filter Data During Processing

#!/bin/bash

# Read CSV and skip invalid records
csv_file="$1"

while IFS=',' read -r id name age; do
  [ "$id" = "id" ] && continue              # Skip header
  [ -z "$id" ] && continue                  # Skip empty lines
  [ "$age" -lt 18 ] && continue             # Skip minors
  [[ "$name" =~ ^[A-Za-z]+ ]] || continue   # Skip invalid names

  # Process valid record
  echo "Adult: $name ($age)"
done < "$csv_file"

Example 3: Skip Lines Matching Pattern

#!/bin/bash

# Process log file, skip certain log levels
log_file="$1"

while IFS= read -r line; do
  # Skip debug messages
  [[ "$line" =~ \[DEBUG\] ]] && continue

  # Skip info messages
  [[ "$line" =~ \[INFO\] ]] && continue

  # Process warnings and errors
  echo "$line"
done < "$log_file"

Example 4: Validate and Process Data

#!/bin/bash

# Read data, validate, and skip invalid entries
while IFS=',' read -r email username; do
  # Skip header
  [ "$email" = "email" ] && continue

  # Validate email format (simple)
  [[ "$email" =~ ^[^@]+@[^@]+\.[a-z]+$ ]] || continue

  # Validate username length
  [ ${#username} -lt 3 ] && continue
  [ ${#username} -gt 20 ] && continue

  # All validations passed
  echo "Valid: $username <$email>"
done < users.csv

Example 5: Skip Until Condition Met

#!/bin/bash

# Skip lines until finding marker
while IFS= read -r line; do
  # Skip until we find the marker
  if [ "$line" = "START" ]; then
    continue  # Skip START line itself
  fi

  # Still skipping
  if [ "$start_found" != "true" ]; then
    continue
  fi

  # Now process
  echo "Processing: $line"

done < input.txt

Better approach:

#!/bin/bash

# Skip lines until marker (better pattern)
found_marker=false

while IFS= read -r line; do
  if [ "$line" = "START" ]; then
    found_marker=true
    continue
  fi

  # Skip until marker found
  [ "$found_marker" = false ] && continue

  # Process after marker
  echo "Processing: $line"

done < input.txt

Example 6: Function with Continue

#!/bin/bash

# Function using continue in loop
process_items() {
  local -a items=("$@")

  for item in "${items[@]}"; do
    # Skip empty items
    [ -z "$item" ] && continue

    # Skip items starting with underscore
    [[ "$item" =~ ^_ ]] && continue

    # Process item
    echo "Processing: $item"
  done
}

# Usage
process_items "apple" "_hidden" "banana" "" "cherry"

# Output:
# Processing: apple
# Processing: banana
# Processing: cherry

Example 7: Multi-Level Continue

#!/bin/bash

# Example: Search directory tree, skip certain files
for dir in ./*/; do
  [ -d "$dir" ] || continue

  for file in "$dir"*; do
    # Skip hidden files
    [[ "$(basename "$file")" =~ ^\. ]] && continue

    # Skip backup files
    [[ "$file" =~ \.bak$ ]] && continue

    # Skip large files
    [ -s "$file" ] && [ $(stat -c%s "$file") -gt 1000000 ] && continue

    # Process file
    echo "Processing: $file"
  done
done

Performance Comparison

Using continue vs other methods:

ApproachUse Case
continueSkip iteration, process remainder
if/elseExecute conditional block
grep -vFilter lines (external tool)
sedComplex filtering

Best choice: Use continue for filtering within loops.

Difference: continue vs break vs return

StatementEffect
continueSkip to next iteration
continue NSkip N loop levels
breakExit loop completely
returnExit function
exitExit script

Important Considerations

Continue Level Must Exist

Specifying continue level must not exceed nesting depth:

for i in {1..3}; do
  if [ $i -eq 2 ]; then
    continue 3  # Error: only 1 level deep
  fi
done
# bash: continue: 3: loop level too high

Performance with Many Continues

Many continues can make code harder to read. Consider alternatives:

# Many continues - hard to follow
for line in lines; do
  [ -z "$line" ] && continue
  [[ "$line" =~ ^# ]] && continue
  [ "$count" -gt 100 ] && continue
  echo "Process"
done

# Better: use grep or awk
grep -v '^ *$' | grep -v '^#' | ...

Continue in case Statements

While continue works in loops within case statements, it doesn’t work inside case itself:

#!/bin/bash

for item in list; do
  case $item in
    skip_me)
      continue  # Works: continue outer loop
      ;;
    process)
      echo "Processing: $item"
      ;;
  esac
done

Quick Reference

Patterns for skipping iterations:

# Skip single iteration
for i in list; do
  [ condition ] && continue
done

# Skip in while loop
while read line; do
  [ condition ] && continue
done

# Skip empty lines
while read line; do
  [ -z "$line" ] && continue
done

# Skip comments
while read line; do
  [[ "$line" =~ ^# ]] && continue
done

# Continue nested loop (both levels)
for i in list; do
  for j in list; do
    [ condition ] && continue 2
  done
done

Summary

The continue statement is your filtering tool. Use it early and often when processing data—skip empty lines, skip comments, skip invalid entries. Multiple continue statements at the top of a loop make your intent clear: “process only this data.” For nested loops needing multi-level skipping, use continue 2 or continue 3. Always document why you’re skipping with clear conditions so the next person reading your code understands the filtering logic.

#!/bin/bash

# Pattern for filtering while processing
while IFS= read -r line; do
  # Skip empty lines
  [ -z "$line" ] && continue

  # Skip comments
  [[ "$line" =~ ^# ]] && continue

  # Now process valid line
  process_line "$line"
done < input.txt