Bash For Loop: Syntax and Examples

By 

Updated on

8 min read

Bash for loop syntax examples in a terminal

Loops are a fundamental concept in programming languages. They allow you to execute a series of commands repeatedly until a specific condition is met.

In scripting languages like Bash, loops are especially useful for automating repetitive tasks, eliminating the need to duplicate code.

There are three basic loop constructs in Bash scripting: for loop, while loop , and until loop .

This guide focuses on the for loop in Bash, including its syntax variations, nesting, flow-control statements like break and continue, and practical examples.

The Standard Bash for Loop

The for loop iterates over a list of items and performs the given set of commands.

The basic Bash for loop syntax is:

txt
for item in [LIST]
do
  [COMMANDS]
done

The [LIST] can be a series of strings separated by spaces, a range of numbers, command output, an array, command-line arguments, and so on.

Loop Over Strings

The example below shows a loop that iterates over a list of strings. The loop operates on each item in the list, and the variable element stores the item that the loop is currently processing.

sh
for element in Hydrogen Helium Lithium Beryllium
do
  echo "Element: $element"
done
output
Element: Hydrogen
Element: Helium
Element: Lithium
Element: Beryllium

Loop Over a Range

You can use the sequence expression to specify a range of numbers or characters by defining the start and end point of the range. The sequence expression takes the following form:

txt
{START..END}

Here is an example loop that iterates through all numbers from 0 to 3:

sh
for i in {0..3}
do
  echo "Number: $i"
done
output
Number: 0
Number: 1
Number: 2
Number: 3

Bash also supports specifying an increment when using ranges:

txt
{START..END..INCREMENT}

Here is an example showing how to increment by 5:

sh
for i in {0..20..5}
do
  echo "Number: $i"
done
output
Number: 0
Number: 5
Number: 10
Number: 15
Number: 20

Loop Over Array Elements

You can use the for loop to iterate over the elements of a Bash array .

In the example below, we define an array named BOOKS and iterate over each element of the array.

sh
BOOKS=('In Search of Lost Time' 'Don Quixote' 'Ulysses' 'The Great Gatsby')

for book in "${BOOKS[@]}"; do
  echo "Book: $book"
done
output
Book: In Search of Lost Time
Book: Don Quixote
Book: Ulysses
Book: The Great Gatsby

The C-style for Loop

Bash also supports a C-style for loop syntax:

txt
for ((INITIALIZATION; TEST; STEP))
do
  [COMMANDS]
done

The INITIALIZATION part is executed only once when the loop starts. Then, the TEST part is evaluated using comparison operators . If it is false, the loop is terminated. If the TEST is true, commands inside the body of the for loop are executed, and the STEP part is updated.

In the following example, the loop starts by initializing i = 0 and, before each iteration, checks whether i ≤ 10. If true, it prints the current value of i and increments i by 1 (i++). Otherwise, the loop terminates.

sh
for ((i = 0 ; i <= 10 ; i++)); do
  echo "Counter: $i"
done

The loop iterates 11 times and produces the following output:

output
Counter: 0
Counter: 1
Counter: 2
...
Counter: 8
Counter: 9
Counter: 10

Nested Loops

A nested loop is a loop inside another loop. You can nest loops to any depth.

In a nested for loop, the inner loop runs a complete cycle of its iterations for every outer loop iteration.

Here is an example that copies three files one by one to three servers:

sh
for f in file_{1..3}; do
  for j in server_{1..3}; do
    echo "Copying file $f to server $j"
    # command to copy files
  done
done
output
Copying file file_1 to server server_1
Copying file file_1 to server server_2
Copying file file_1 to server server_3
Copying file file_2 to server server_1
Copying file file_2 to server server_2
Copying file file_2 to server server_3
Copying file file_3 to server server_1
Copying file file_3 to server server_2
Copying file file_3 to server server_3

Controlling Loop Flow: break and continue

The break and continue statements are used to control the execution of a for loop.

break – Terminate the Loop

The break statement terminates the current loop and passes control to the statement that follows it. It is generally used to exit the loop when a specific condition is met.

In the following example, the if statement terminates the loop once the current item is equal to Lithium:

sh
for element in Hydrogen Helium Lithium Beryllium; do
  if [[ "$element" == 'Lithium' ]]; then
    break
  fi
  echo "Element: $element"
done

echo 'All Done!'
output
Element: Hydrogen
Element: Helium
All Done!

continue – Skip to the Next Iteration

The continue statement exits the current iteration and passes control to the next one.

In the following example, when the current item equals 2, the continue statement skips the echo and moves to the next iteration:

sh
for i in {1..5}; do
  if [[ "$i" == '2' ]]; then
    continue
  fi
  echo "Number: $i"
done
output
Number: 1
Number: 3
Number: 4
Number: 5

Real-World Examples

Rename Files with Spaces in the Name

The following example renames all files in the current directory that contain a space, replacing spaces with underscores:

sh
for file in *\ *; do
  mv "$file" "${file// /_}"
done
  • *\ * matches all filenames that contain a space.
  • ${file// /_} uses shell parameter expansion to replace every space with an underscore.

Change File Extension

The following example renames all files ending in .jpeg in the current directory, replacing the extension with .jpg:

sh
for file in *.jpeg; do
  mv -- "$file" "${file%.jpeg}.jpg"
done
  • *.jpeg matches all .jpeg files in the current directory.
  • ${file%.jpeg} strips the .jpeg suffix using shell parameter expansion, and .jpg is appended to form the new name.
  • The -- flag prevents mv from misinterpreting filenames that start with a dash as options.

Restart Multiple Docker Containers

Here is an example that restarts a list of containers after deploying new code:

sh
for container in web db cache redis; do
  docker restart "$container" && echo "Restarted $container"
done

Containers are passed to the loop as a list of strings.

Troubleshooting

Loop splits a filename or string with spaces into multiple items Without quotes, Bash performs word splitting on spaces. Always quote variables and array expansions: use "${ARRAY[@]}" instead of ${ARRAY[@]}, and "$file" instead of $file.

Glob pattern in the list expands unexpectedly When a glob pattern like *.jpeg matches no files, Bash passes the literal string *.jpeg to the loop variable. Add shopt -s nullglob before the loop to make unmatched globs expand to nothing instead.

C-style loop does not behave like expected with [[ ]] The C-style loop uses arithmetic evaluation — comparisons inside (( )) use <, >, and == directly. Do not mix [[ ]] test syntax inside the loop initializer or condition.

Range with a variable does not expand Brace expansion happens before variable substitution, so {1..$N} does not work. Use a C-style loop or seq instead: for i in $(seq 1 "$N"); do.

Quick Reference

SyntaxDescription
for item in a b c; do ... doneLoop over a list of strings
for i in {1..10}; do ... doneLoop over a numeric range
for i in {0..20..5}; do ... doneLoop over a range with increment
for item in "${ARRAY[@]}"; do ... doneLoop over array elements
for ((i=0; i<10; i++)); do ... doneC-style loop
breakExit the loop immediately
continueSkip to the next iteration

FAQ

What is the difference between the standard for loop and the C-style for loop? The standard for loop iterates over a list of items (strings, array elements, a range). The C-style for loop uses arithmetic initialization, condition, and step expressions — it is better suited for counter-based iteration where you control the start, end, and step explicitly.

How do I loop over lines in a file? Use a while loop with read instead: while IFS= read -r line; do echo "$line"; done < file.txt. A for loop is not suited for line-by-line file reading because it splits on whitespace, not newlines.

Can I use break or continue in nested loops? Yes. By default, break and continue affect only the innermost loop. To exit an outer loop from an inner one, use a numeric argument: break 2 exits two levels of nesting.

How do I loop over command-line arguments? Use for arg in "$@"; do to iterate over all positional parameters passed to the script.

Conclusion

The Bash for loop iterates over a list of items or runs for a defined number of iterations using C-style syntax. Combined with break, continue, nesting, and parameter expansion, it enables elegant solutions to many automation tasks.

To learn all the ways to run your scripts, see How to Run a Bash Script .

If you have any questions, feel free to leave a comment below.

Tags

Linuxize Weekly Newsletter

A quick weekly roundup of new tutorials, news, and tips.

About the authors

Dejan Panovski

Dejan Panovski

Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.

View author page