Bash For Loop: Syntax and Examples

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:
for item in [LIST]
do
[COMMANDS]
doneThe [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.
for element in Hydrogen Helium Lithium Beryllium
do
echo "Element: $element"
doneElement: Hydrogen
Element: Helium
Element: Lithium
Element: BerylliumLoop 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:
{START..END}Here is an example loop that iterates through all numbers from 0 to 3:
for i in {0..3}
do
echo "Number: $i"
doneNumber: 0
Number: 1
Number: 2
Number: 3Bash also supports specifying an increment when using ranges:
{START..END..INCREMENT}Here is an example showing how to increment by 5:
for i in {0..20..5}
do
echo "Number: $i"
doneNumber: 0
Number: 5
Number: 10
Number: 15
Number: 20Loop 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.
BOOKS=('In Search of Lost Time' 'Don Quixote' 'Ulysses' 'The Great Gatsby')
for book in "${BOOKS[@]}"; do
echo "Book: $book"
doneBook: In Search of Lost Time
Book: Don Quixote
Book: Ulysses
Book: The Great GatsbyThe C-style for Loop
Bash also supports a C-style for loop syntax:
for ((INITIALIZATION; TEST; STEP))
do
[COMMANDS]
doneThe 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.
for ((i = 0 ; i <= 10 ; i++)); do
echo "Counter: $i"
doneThe loop iterates 11 times and produces the following output:
Counter: 0
Counter: 1
Counter: 2
...
Counter: 8
Counter: 9
Counter: 10Nested 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:
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
doneCopying 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_3Controlling 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:
for element in Hydrogen Helium Lithium Beryllium; do
if [[ "$element" == 'Lithium' ]]; then
break
fi
echo "Element: $element"
done
echo 'All Done!'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:
for i in {1..5}; do
if [[ "$i" == '2' ]]; then
continue
fi
echo "Number: $i"
doneNumber: 1
Number: 3
Number: 4
Number: 5Real-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:
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:
for file in *.jpeg; do
mv -- "$file" "${file%.jpeg}.jpg"
done*.jpegmatches all.jpegfiles in the current directory.${file%.jpeg}strips the.jpegsuffix using shell parameter expansion, and.jpgis appended to form the new name.- The
--flag preventsmvfrom 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:
for container in web db cache redis; do
docker restart "$container" && echo "Restarted $container"
doneContainers 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
| Syntax | Description |
|---|---|
for item in a b c; do ... done | Loop over a list of strings |
for i in {1..10}; do ... done | Loop over a numeric range |
for i in {0..20..5}; do ... done | Loop over a range with increment |
for item in "${ARRAY[@]}"; do ... done | Loop over array elements |
for ((i=0; i<10; i++)); do ... done | C-style loop |
break | Exit the loop immediately |
continue | Skip 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 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