Bash For Loop: Syntax and Examples

Updated on

6 min read

Bash For Loop

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 the 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]
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 operating on.

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

The loop will produce the following 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 the 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"
done
Number: 0
Number: 1
Number: 2
Number: 3

Starting from Bash 4, you can also specify an increment when using ranges:

{START..END..INCREMENT}

Here’s an example showing how to increment by 5:

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

Loop over array elements

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

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"
done
Book: In Search of Lost Time
Book: Don Quixote
Book: Ulysses
Book: The Great Gatsby

The C-style for loop

Bash for loop also supports a C-like syntax:

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

The INITIALIZATION part is executed only once when the loop starts. Then, the TEST part is evaluated. 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 code, 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 the variable i by 1 (i++). Otherwise, the loop terminates.

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

The loop will iterate 1001 times and produce the following output:

Counter: 0
Counter: 1
Counter: 2
...
Counter: 998
Counter: 999
Counter: 1000

Nested Loops

A nested loop is a loop inside another loop. You can nest any loop any number of times.

In a nested for loop, the inner loop runs a complete cycle of its iterations for every outer loop iteration. This means that for every execution of the outer loop, the inner loop will execute all of its iterations until the outer loop completes its cycle.

Here’s an example code 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; 
done
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 Statements

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

break – terminate the loop entirely

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

In the following example, we use the if statement to terminate the execution of the loop once the current iterated 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 of a loop and passes program control to the next iteration of the loop.

In the following example, we iterate through a range of numbers. When the current iterated item is equal to ‘2’, the continue statement will cause execution to return to the beginning of the loop and to continue with the next iteration:

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

Real-World Examples

  1. Renaming files with spaces in the filename

    The following example shows how to rename all of the files in the current directory with a space in their names by replacing the spaces with underscores:

    for file in *\ *; do
      mv "$file" "${file// /_}"
    done
    

    Let’s break down the code line by line:

    • The first line creates a for loop that iterates over a list of all files with a space in their names. (The expression *\ * creates the list).
    • The second line applies to each item in the list and renames the file, replacing spaces with underscores (_). The part ${file// /_} is using the shell parameter expansion to replace a pattern within a parameter with a string.
    • done indicates the end of the loop segment.
  2. Changing file extension

    The following example shows how to use a Bash for loop to rename all files ending with .jpeg in the current directory, replacing the file extension from ‘.jpeg’ to ‘.jpg’.

    for file in *.jpeg; do
        mv -- "$file" "${file%.jpeg}.jpg"
    done
    

    Let’s analyze the code line by line:

    • The first line creates a for loop that iterates through a list of all files ending in ‘.jpeg’.
    • The second line applies to each item in the list and moves the file to a new one, replacing ‘.jpeg’ with ‘.jpg’. The expression ${file%.jpeg} removes the ‘.jpeg’ part from the filename using the shell parameter expansion
    • done indicates the end of the loop segment.
  3. Restart multiple Docker containers

    Here is an example that can be useful after deploying new code and you want to restart more than one container:

    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.

Conclusion

The Bash for loop is used to execute a given set of commands repeatedly for a fixed number of times. Combined with break, continue, nesting, and parameter expansion, it enables elegant solutions to many automation tasks.

Mastering for loops will significantly boost your Bash scripting skills. Happy scripting!