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:
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:
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:
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:
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:
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:
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:
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:
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[@]}”.
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:
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:
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:
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:
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:
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:
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.