Skip to main content

Learn Bash Scripting

Chapter #8: How to Use for and while Loops in Bash Scripting

Learn how to use for loops, while loops, and the continue command in Bash to automate tasks, rename files, and write efficient shell scripts.

Until now, we’ve explored some game-changing concepts in our Bash scripting journey. As we said before, Bash is a fun scripting language that aims to make our automation and Linux controlling easier and more enjoyable.

Today, we're diving into one of the most powerful tools in any scripting language - loops. You might’ve heard them called iterations in other languages, and honestly, they’re everywhere. From checking files in a folder to running a command multiple times, loops help you repeat tasks without repeating yourself.

In this chapter, we’re going to learn how to write for loops and while loops in Bash. We’ll break it down with real-life examples, show you where they shine, and how to make your scripts way more efficient and smarter using them.

What are Loops

Loops let us perform a task over and over again, which is super handy when you don’t want to write the same line of code ten times. Unlike if statements (which only run something once if a condition is true), loops keep running a block of code until a certain condition is no longer true.

Just like in other programming languages, Bash gives us a few different types of loops to choose from. Each one has its own style, purpose, and best use case, but they all help us repeat tasks in a smarter way.

The for Loop

The first type of loop we're going to explore is the for loop. In simple terms, a for loop lets us repeat a block of code over and over until we reach a specific condition that tells it to stop.

Here’s the basic syntax of a for loop in Bash:

for [condition]; do
    # block of code to repeat
done

Just like we saw with if statements, the for loop starts with the keyword for, followed by the condition or the list it will loop through.

Then we use the keyword do to start the repeating code block (yep, I keep saying block - it just means a chunk of code that runs together 😅).

After writing what we want to repeat, we wrap it all up with the keyword done, which tells Bash, “Okay, I’m finished with this loop.

You can picture it like this:

for item in list; do
    echo "$item"
done
Working of for loop in Bash

Here, we’re going to demonstrate how to repeat a string 5 times. Let's write this in a simple Bash script to see how the syntax works:

for i in {1..5}
do 
    echo "TecMint"
done

Let’s break it down:

  • We start the loop with the keyword for and use a variable called i. You can actually name this variable whatever you like - i is just a common choice because it stands for “index” or “iterator.”
  • The {1..5} part creates a sequence from 1 to 5. Think of it as a shortcut for {1,2,3,4,5} - but way cleaner and easier to scale. This is Bash doing the counting for you.
  • Then we use do to start our block of code, which in this case is just a simple echo "TecMint".
  • This block will run once for each number in the range. So yep, "TecMint" will be printed 5 times.
  • Finally, we end the loop with done to let Bash know we’re finished with the loop body.

We can visualize this like a little cycle:

i = 1  -> echo "TecMint"
i = 2  -> echo "TecMint"
i = 3  -> echo "TecMint"
i = 4  -> echo "TecMint"
i = 5  -> echo "TecMint"

Each time, the value of i changes, and the same command runs again. Super handy when you need to repeat things without copy-pasting code a million times.

Your First for Loop in Action

When we run this example, we should get an output like this:

Looping Through a Number Range
💡
Note: Using a semicolon (;) is also a valid syntax:
for i in {1..5}; do 
    echo "TecMint"
done

However, for best practices and better readability, it is recommended to use the first format.

To make our example clearer, we can print the i variable alongside the name "TecMint" like this:

for i in {1..5}; do 
    echo "$i: TecMint"
done

Now, if we run this, it should make sense:

1: TecMint
2: TecMint
3: TecMint
4: TecMint
5: TecMint

We print the value of the variable each time alongside the name.

Up to this point, you’ve got a pretty good idea of what a for loop is and how it helps make our code more dynamic, especially when it comes to automation. It's one of those things that turns repetitive tasks into quick wins.

Now, the last example was nice and simple — a good way to get comfortable. But let’s take it up a notch and look at something you’ll definitely run into as a system administrator.

Imagine you have a bunch of files — let’s say four for now, but it could be 40 or 400 in real scenarios. These files are named like file1.txt, file2.txt, and so on. Your task is to rename all of them by adding the word bash at the beginning, so they become bashfile1.txt, bashfile2.txt, etc.

Sounds like a pain to do manually, right?

Well, this is where for loops shine. Here's a simple script that does the job:

for file in file*.txt
do
    mv "$file" "bash${file%.txt}.txt"
done

Let’s break it down:

  • for file in file*.txt:
    This part will loop over every file in the current directory that starts with “file” and ends with “.txt”.
    The variable file will hold one filename at a time during each loop.
  • mv "$file" "bash${file%.txt}.txt":
    This is the command that does the actual renaming.
    mv is the move command, but it’s also used to rename files.
    The first part, "$file", is the original name.
    The second part, "bash${file%.txt}.txt", is the new name.
    • ${file%.txt} removes the .txt part from the end
    • Then we add "bash" in front of it
    • Finally, we reattach .txt at the end.

So file1.txt becomes bashfile1.txt, just like magic.

This might look a bit tricky at first, but once you get it, you'll start seeing how powerful these little scripts can be. A few lines of code, and boom - a whole batch of files renamed in seconds!

Now let’s check if this whole thing actually works by creating 4 simple files.

touch file1.txt file2.txt file3.txt file4.txt

Next up, let’s create a new Bash script. You can name it whatever you like, but for this example, let’s call it loop.sh.

#!/bin/bash

for file in file*.txt
do
    mv "$file" "bash${file%.txt}.txt"
done

Save the file, permit it to run:

bash loop.sh

You should see something like:

-rw-rw-r-- 1 ravi ravi   0 Apr 16 13:28 bashfile1.txt
-rw-rw-r-- 1 ravi ravi   0 Apr 16 13:28 bashfile2.txt
-rw-rw-r-- 1 ravi ravi   0 Apr 16 13:28 bashfile3.txt
-rw-rw-r-- 1 ravi ravi   0 Apr 16 13:28 bashfile4.txt
-rw-rw-r-- 1 ravi ravi  44 Apr 11 13:21 bashfile.txt

And boom - you just renamed all your files in one go. No clicking, no renaming one by one. Just one script, and you’re done.

The while Loop

A while loop is kind of like a for loop. By loop, we mean that a block of code will keep running until a certain condition is no longer true.

The syntax of a while loop is a bit different from a for loop, but the core idea is exactly the same - repeating a task until a condition is met.

Here’s how it looks:

a=10

while [ $a -le 15 ]
do
    echo $a
    (( a++ ))
done

The syntax looks pretty close to a for loop, right? We start the loop with the keyword while, followed by the condition (inside square brackets).

In the condition, we’re basically saying:

"While the value of variable $a is less than or equal to (-le) 15, keep doing this..."

Let’s break down the rest:

  • echo $a: This prints the current value of the variable a.
  • (( a++ )): This increments the value of a by 1. So every time the loop runs, a gets one step closer to 15.
  • done: Just like with the for loop, this tells Bash that we’re done with the loop block.

Since we started the variable with a=10, the loop will count from 10 up to 15. So the output will look like this:

10
11
12
13
14
15

Note: The while loop will keep running until the condition we set becomes false. If the condition never becomes false, the loop will continue running forever - that’s what we call an infinite loop.

Now, you might be wondering:

"What if the condition or test we write isn’t true to begin with? What happens then?"

Great question! If the condition is not true right from the start, the while loop simply won’t run at all. It checks the test first, and if it fails, it skips the loop entirely.

Let’s look at an example to make this clear:

a=20

while [ $a -le 15 ]
do
    echo $a
    (( a++ ))
done

In this case, $a starts at 20, and we’re checking if it's less than or equal to 15, which it’s not. So the loop will never run, and you won’t see any output.

Let’s say a=20, and we check if it’s less than or equal to 15. That condition is false right from the start. So, the loop won’t even run. Remember: a while loop only runs if the condition is true at the beginning.

Inside a while loop, just like a for loop, we can put whatever we want - even an if statement.

Let’s look at a more practical example.

Say we want to repeat our previous loop, but this time we want to:

  • Start counting from 1 up to 20.
  • Only print the numbers that are divisible by 2 (i.e., even numbers).

We can totally do that by placing an if statement inside the while loop.

Check this out:

a=1
while [ $a -le 20 ]
do
    if [ $((a % 2)) -ne 0 ]; then
        ((a++))
        continue
    fi
    echo "$a"
    ((a++))  
done

Now, this might look a bit complex at first glance - so let’s break it down line by line:

  • a=1: We start by setting our variable a to 1.
  • while [ $a -le 20 ]: This loop will keep running as long as a is less than or equal to 20.
  • if [ $((a % 2)) -ne 0 ]; then: Here we check if a is odd. We use the modulo operator % to see if there's a remainder when we divide a by 2. If the result is not equal (-ne) to 0, it's an odd number.
    • ((a++)): We increase a by 1.
    • continue: This tells Bash to skip the rest of the loop and go back to the top.
  • If the number is even, the if block is skipped, and we go straight to:
    • echo "$a": This prints the even number.
    • ((a++)): Then we increment a.

Now you might be thinking:

"Wait, why are there two a++ lines?"

Great question! If you’re asking this, it means you’re paying attention - nice work!

Here’s the deal: Only one of those a++ lines runs at a time.

  • If the number is odd, we increment inside the if block and continue skips the rest.
  • If the number is even, the if block is skipped, and the increment happens after printing.

Let’s walk through the first iteration when a=1 to make it crystal clear:

  • a=1, which is odd
  • Condition is true, so it goes into the if block
  • ((a++)) makes a=2
  • continue skips the rest of the loop
  • Next loop: a=2, which is even
  • It skips the if block, prints 2, then increments to 3

...and so on, until a reaches 21, and the loop ends.

To make it clearer, the first iteration where a = 1 will be like this:

What Happens When a = 1?

The next iteration where a = 2 will be like this:

Breaking Down the Next Iteration: When a = 2

The final output will be like this:

2
4
6
8
10
12
14
16
18
20

What Does continue Do?

You might be wondering - what exactly does the continue statement do inside a while loop?

Well, as we mentioned earlier, the continue command is used to skip the rest of the code inside the loop for that specific iteration, and then it jumps straight to the next round of the loop.

Let’s clear this up with an example. Suppose we want to print numbers from 0 to 6, but we want to skip the number 4.

Here’s how we can do that using continue:

a=0
while [ $a -le 6 ]
do
    if [ $a -eq 4 ]; then
        ((a++))   
        continue  
    fi
    echo "$a"
    ((a++))
done

Here’s what’s happening:

  • We’re looping while $a is less than or equal to 6.
  • Inside the loop, we check if $a equals 4.
  • If it does, we increment a (so we don't get stuck in an infinite loop) and then use continue to skip the echo command.
  • That means 4 doesn’t get printed, but all other numbers do.

When you run this script, the output will look like:

0
1
2
3
5
6

Summary

In this lesson, we learned how to use the for loop, while loop, and the continue statement to make our Bash scripts more dynamic and flexible.

In the next chapter, we’ll take things further and explore more advanced loop tricks and iteration patterns in Bash scripting. Stay tuned!