Bash Scripting For Loop

Bash-For-Loops-feature-image.jpg

Scripting is most commonly used to automate routine tasks, making you more efficient. The routine functions usually consist of code that is repeated. In such cases, Bash for Loops helps execute repetitive tasks efficiently by iterating over commands multiple times. In this article, we will learn about Bash for Loops and how to implement them in Bash Scripting. We will also look at a few examples to solidify your understanding and explore best and worst practices when working with them.  

Introduction to Bash for Loops

When working with Bash Scripting and task automation, you will come across many different repetitive tasks. Instead of writing multiple lines of code again and again, it is better to use loops to make your code more readable and efficient. 

Bash for loop is the most common and widely used loop while scripting. It allows you to iterate over a series of values, whether they are numbers, strings, files, or the output of commands, and perform actions on each item in turn. It saves you the time of writing similar code for each file, string, or element. 

For example, imagine you need to rename hundreds of files, process log files, or ping multiple servers. Without loops, you’d have to write one command per file or server, which is impractical. With a for loop, you can handle the entire set in just a few lines of code.

Now, let us understand the various kinds of for loops you can use in Bash scripting, starting with the most basic kind that you might have seen in other programming languages as well.

Simple Bash for Loop Examples

In the simplest Bash for loop, you provide the list of elements to iterate through and a task that you must perform on these items. The list can contain numerics, strings, or files. This is done using the following syntax:

Syntax:

for item in list
do
    # commands to execute on $item
done

Here:

  • item is the loop variable that takes the value of each element from the list one by one.
  • The list is the set of values you want to iterate through.
  • The commands inside the do … done block will execute for each value of item.

Let us look at some bash for loop examples and how it is implemented.

Example 1:

In this example, we will work with a list of strings and iterate over them using a Bash for loop. If there was a list of numbers also the code would have run the same.

for color in red blue green yellow
do
    echo "Color: $color"
done

Output:

Simple Bash For Loop Example

Explanation: Here we had a list of colors and a variable “color” to iterate through this list. While traversing, we printed (or echoed) each color on the shell. 

Example 2:

Now, let us see how you can iterate through files and run a command on each item.

for file in file1.txt file2.txt file3.txt
do
    echo "Processing $file..."
    cat "$file"
done

Output:

Simple Bash For Loop Example 2

Explanation: The “$cat” command opens the files and displays the contents of that file. Here, since I have no file1.txt, file2.txt, they threw the “No such file” error. But for the third file, since it was available, it was processed and displayed successfully. 

But what if the list of values you want to iterate through is too long to type manually? Imagine you need to loop through numbers from 1 to 100, or even 1 to 10,000. Typing each value would be impractical. In such cases, Bash provides range-based for loops, which let you generate sequences automatically and loop through them efficiently.

Bash Range-Based for Loops

You can use Bash Range-Based for loops when the list you are iterating over is sequential in nature, such as counting from 1 to 10 or processing files labeled file1 through file100. For sequential data, a range-based for loop is better than a simple bash for loop, as it automatically generates that sequence. 

Syntax:

for number in {start..end..step}
do
    # Commands to execute on $number
done

Here, 

  • You give the range in curly braces {..}. Add the start of the range and the end of that range.
  • You can also add an optional step value if you want to increment in a uniform interval. 
Note that this works in Bash 4+, not in older versions.

Let us implement all the examples that we implemented using simple Bash for loops using the range-based for loops. 

Example 1:

for number in {1..5}
do
    echo "Number: $number"
done

Output:

Bash Range-Based for Loops

Explanation: Here, we used the range instead of a list of numbers to iterate since the numbers were in sequence. 

Example 2:

What if you wanted to print all the even numbers in a range? We can iterate through the range of elements in steps of two.

for number in {0..10..2}
do
    echo "Even number: $number"
done

Output:

Bash Range-Based for Loops Example 2

Explanation: In this example, we printed even numbers by iterating over the range in steps of two and printing them. 

But such loops are not good for initializing variables, setting complex conditions, or using custom increments. For such cases, Bash provides a C-style for loop that works much like a traditional for loop in C, C++, or Java and is more flexible.

C-Style for Loop in Bash

Simple for loops and range-based for loops are limited to a simple start-end sequence. C-style loops in Bash give you more flexibility and control over the increment conditions. You can also choose a different variable initialization. The syntax looks similar to the for loops in C.

Syntax:

for (( initialization; condition; increment ))
do
    # commands
done
  • initialization: This parameter sets the starting point (e.g., i=0)
  • condition: This argument defines when the loop should stop (e.g., i<5)
  • increment: This updates the loop variable after each iteration (e.g., i++)
Note: Always remember to double-check your increment and condition. A wrong condition or increment might convert your loop into an infinite loop. 

Let us see an example of applying any arithmetic calculations to the loops, which was not possible with range-based and simple for loops.

Let us calculate the square of even numbers till 20.

Example:

for (( i=0; i<=20; i+=2 ))
do
    square=$(( i * i ))
    echo "Square of $i is $square"
done

Output:

C Style For Loop in Bash

Explanation: In the above example, we are incrementing in steps of two and finding the square of all the even numbers using a Bash C-style for loop.

Sometimes you may need to run a loop inside a loop. In such cases, you can use Nested loops in Bash scripting.

Nested for Loops in Bash

Nested for loops help you when you may need to process data arranged in rows and columns, perform combinations of values, or generate structured outputs. You simply place one loop inside another loop. A nested loop means:

  • The outer loop runs first and controls the number of iterations.
  • For each iteration of the outer loop, the inner loop runs completely.

This is especially useful when you are working with structures like matrices, pattern combinations, or handling multi-dimensional data.   

Syntax:

for outer in list1
do
    for inner in list2
    do
        # commands using $outer and $inner
    done
done

Let us try to print a grid of numbers in rows and columns using nested loops in Bash scripting.

Get 100% Hike!

Master Most in Demand Skills Now!

Example:

for (( i=1; i<=3; i++ ))
do
    for (( j=1; j<=3; j++ ))
    do
        echo -n "$i$j "
    done
    echo
done

Output:

Nested for Loops in Bash

Explanation: In this example, as you can see, the row number and the column number are being printed. This results in a two-dimensional array of numbers. Here, first, the value of i is printed, and then the value of j is printed next. 

Example 2: 

Nested loops can also be used for combinations of array values. This is very handy when dealing with datasets where every element needs to be combined with every other element.

#!/bin/bash

fruits=("apple" "banana" "cherry")
colors=("red" "green" "yellow")
for fruit in "${fruits[@]}"
do
    for color in "${colors[@]}"
    do
        echo "$fruit - $color"
    done
done

Output:

Nested for Loops in Bash Example 2

Explanation: Here, we are mapping each element of the fruit list to each element of the color list. Doing this with any other for loop would have been more complex. 

Bash for Loop with Arrays

When you want to store multiple values under the same name, arrays in Bash are the best way to do that. You can use it to handle lists of data such as filenames, usernames, server IPs, or any other collection of related items. Before we understand how the for loop works with an array, let us briefly look at how to declare an array. There are several ways to declare an array: 

  • You can declare an array by directly assigning values in parentheses, for example: fruits=(“apple” “banana” “cherry”).
  • You can create an empty array first and then add elements to it incrementally.
  • You can explicitly declare an array using the declare -a command, for example: declare -a colors=(“red” “green” “blue”)

Let us see through code how it is done.

# Declare an array with values
fruits=("apple" "banana" "cherry")

# Declare an empty array and add elements later
numbers=()
numbers+=(10)
numbers+=(20)
numbers+=(30)

# Explicitly declare an array using declare -a
declare -a colors=("red" "green" "blue")

Output:

Bash for Loop with Arrays

As you can see, nothing has been displayed on the screen. However, since there are no errors displayed on the screen, the arrays were initialized in memory.

To access a single element, we use echo “${fruits[0]}”. And, to display the elements, we can use the echo “${fruits[@]}”.

Access elements in an Array in Bash

Using Bash for loops, you can iterate through the whole list in the following way:

Example:

colors=("red" "green" "blue")
for index in "${!colors[@]}"
do
    echo "Index: $index, Value: ${colors[$index]}"
done

Output:

For loop in array in Bash

Explanation: Using indices helps you keep track of the positions of elements in dynamic arrays. You can directly access elements as well. 

Bash for Loop Control Statements

Sometimes you might want to control the behaviour of a loop, like stopping at a particular condition or skipping any iteration. To implement these behaviours, you can use control statements like break and continue. These statements give you more flexibility and allow you to fine-tune how loops operate in Bash scripts. Break and continue are also used to manage and avoid an infinite loop. 

break Statement

The break statement immediately terminates the loop and transfers control to the next command. This is useful when you want to stop execution as soon as a condition is met. Let us see how this works with an example.

Example:

#!/bin/bash

for (( i=1; i<=10; i++ ))
do
    if (( i == 5 )); then
        echo "Reached $i, breaking out of the loop."
        break
    fi
    echo "Number: $i"
done

Output:

Break statement Bash loop control statement

Explanation: As specified in the condition, the loop was broken after i=5 became true. The loop stopped, and control was transferred to the “done” command

Another way you can control the loop is by skipping an interaction. This is achieved using the continue statement. 

continue Statement

The continue statement skips the current iteration and moves directly to the next one. This is useful when you want to ignore certain values but keep the loop running. Let’s take an example where we have to print even numbers. We will skip the value that is odd so that it does not print.

Example:

#!/bin/bash

for (( i=1; i<=10; i++ ))
do
    if (( i % 2 != 0 )); then
        continue
    fi
    echo "Even number: $i"
done

Output: 

continue statement Bash loop control statement

To briefly sum up the control statements,

Use break when you need to stop execution immediately after a condition is satisfied, and continue when you want to skip certain iterations but keep looping.

Till here, we have covered everything you need to know regarding Bash for loops. Once you have mastered these concepts, you can easily use for loops in your scripts. 

Real-World Bash for Loop Examples

Let us look at some real-world Bash for loop examples to help you start. 

Example 1: Processing Files in a Directory

Bash for loops are especially useful for scanning logs, cleaning files, or batch processing.

#!/bin/bash

for file in /var/log/*.log
do
    echo "Checking file: $file"
    grep "ERROR" "$file" > /dev/null && echo "Errors found in $file"
done

Output:

Example 1 - Processing Files in a Directory

Explanation: Right now, since I was in the Desktop folder and not the log folder, the error message was printed, because it couldn’t find any log files. 

Example 2: Iterating Over a List of Users

In a professional system, there is usually more than one user using the same setup. The administrators might want to keep track of and check their activity or automate some things when they log in or register. In such scenarios as well, the Bash for loops come in handy. 

#!/bin/bash

users=("garima" "yash" "ayaan")
for user in "${users[@]}"
do
    echo "Creating home directory for $user"
    mkdir -p "/home/$user"
done

Output: 

Example 2: Iterating Over a List of Users

Explanation: In this example, since we did not have the necessary permission to make a directory, an error was thrown. But otherwise, you can clearly see how the loop iterated over all users and attempted to create a directory for each.

Example 3: Pinging Multiple Servers

When you are working with DevOps automation and network monitoring, Bash for loops come in handy.

#!/bin/bash

servers=("192.168.1.1" "192.168.1.2" "192.168.1.3")
for server in "${servers[@]}"
do
    if ping -c 1 "$server" &> /dev/null; then
        echo "Server $server is reachable"
    else
        echo "Server $server is down"
    fi
done

Output:

Example 3 -  Pinging Multiple Servers

Explanation: This simply means that for each IP in the array, the ping -c 1 command did not receive a reply, so the condition failed. Therefore, the script printed “is down” for all of them.

These are all just a few of the many ways you can use Bash for loops in scripting. These loops help you:

  • Automate repetitive system administration tasks.
  • Manage files and directories in bulk.
  • Monitor servers and processes.
  • Simplify DevOps and data processing workflows.

Writing loops isn’t just about making them work. As a developer, you must write code that is efficient, maintainable, and clean. Let’s explore some best practices to follow and common mistakes to avoid when using for loops in Bash. 

Best Practices for Writing Bash for Loops

  • Use Quotes Around Variables: You should always wrap variables in quotes (“$var”) to handle spaces or special characters properly. This prevents unexpected word splitting. In Bash, word splitting is the process by which unquoted variable values are automatically split into separate words based on whitespace. This can break loops or commands unexpectedly.
  • Prefer $(…) over backticks: When capturing command output inside loops, use $(command) instead of backticks (`command`). It is easier to read and nest.
  • Use Meaningful Variable Names: Instead of generic names like item or val, use descriptive ones like file, server, or user. This makes the script more readable for a third person who is reading the code without much context and understanding.
  • Leverage set -e and set -u: You must enable error handling (set -e) and treat unset variables as errors (set -u). This prevents silent failures inside loops.

Common Bash for Loop Errors and Pitfalls

  • Forgetting to Quote Array Expansions: Writing for file in ${files[@]} instead of for file in “${files[@]}” can break your loop if filenames contain spaces. Always remember the quotes. 
  • Using for loops where while loops are Better: Beginners sometimes try to force a for loop when reading files line by line. In this case, a while loop read is safer and more reliable.
  • Not Breaking Out of Infinite Loops: An infinite for loop without proper conditions or break statements can freeze your script and consume resources.
  • Hardcoding Values Instead of Using Variables: Beginners make a habit of writing loops with fixed ranges (like for i in {1..100}) instead of variables. This makes your scripts harder to maintain or reuse.

Conclusion

To conclude, Bash for loops is a powerful scripting tool that will help you automate repetitive tasks, iterate over lists, process arrays, and handle complex workflows with ease. Master the concepts of for loops, from simple iterations to nested loops, and practice their use with the real-world automation examples. Try to avoid the common pitfalls and practice the best practices early on to make that a habit and write professional code. Bash for loops will make your code cleaner, maintainable, and smarter. 

Useful Resources

Bash For Loops – FAQs

Q1. What are Linux shell scripting loops?

Linux shell scripting loops are constructs like for, while, and until used to repeat tasks efficiently within scripts.

Q2. How can automating tasks with Bash loops help?

Automating tasks with Bash loops reduces manual repetition by running commands multiple times, making scripts faster and more reliable.

Q3. What are loop control statements in Bash?

Loop control statements in Bash, like break and continue, allow exiting loops early or skipping iterations for better control.

Q4. How to write efficient Bash scripts using loops?

Writing efficient Bash scripts with loops involves minimizing subshells, avoiding unnecessary commands, and using proper loop constructs.

Q5. What are common examples of loops in Bash scripting?

Examples of loops in Bash scripting include iterating over files, processing text lines, automating backups, and monitoring system resources.

About the Author

Senior Consultant Analytics & Data Science, Eli Lilly and Company

Sahil Mattoo, a Senior Software Engineer at Eli Lilly and Company, is an accomplished professional with 14 years of experience in languages such as Java, Python, and JavaScript. Sahil has a strong foundation in system architecture, database management, and API integration. 

fullstack