Bash for loops are powerful tools in shell scripting that allow you to execute a sequence of commands repeatedly. Whether you’re automating tasks, managing files, or processing data, mastering for loops can significantly enhance your scripting capabilities. This guide will walk you through the basics of bash for loops, complete with simple examples to help you get started.


What is a For Loop?

A for loop in Bash is a control structure that repeats a block of commands for each item in a list. It’s especially useful when you need to perform the same action multiple times with different inputs.


Basic Syntax of a For Loop

The general syntax of a Bash for loop is as follows:

for VARIABLE in ITEM1 ITEM2 ITEM3 ... 
do
    # Commands to execute
done
  • VARIABLE: A placeholder that takes the value of each item in the list, one at a time.
  • ITEM1 ITEM2 ITEM3 …: The list of items you want to iterate over.
  • do … done: The block of commands that will be executed for each item.

Simple Example: Iterating Over a List of Words

Let’s start with a basic example where we print each word in a list.

#!/bin/bash

# Define a list of fruits
fruits="Apple Banana Cherry"

# For loop to iterate over each fruit
for fruit in $fruits
do
    echo "I like $fruit"
done

Explanation:

  1. Define the List: We create a variable fruits containing three items: Apple, Banana, and Cherry.
  2. For Loop: The loop iterates over each fruit in the fruits list.
  3. Echo Statement: For each iteration, it prints “I like [Fruit]”.

Output:

I like Apple
I like Banana
I like Cherry

Example 2: Iterating Over a Range of Numbers

Bash allows you to loop through a sequence of numbers using brace expansion.

#!/bin/bash

# For loop to iterate from 1 to 5
for number in {1..5}
do
    echo "Number: $number"
done

Explanation:

  1. Range: {1..5} generates numbers from 1 to 5.
  2. For Loop: Iterates over each number in the range.
  3. Echo Statement: Prints “Number: [Number]” for each iteration.

Output:

Number: 1
Number: 2
Number: 3
Number: 4
Number: 5

Example 3: Using a For Loop with Command Output

You can use the output of a command as the list for the loop. For example, listing files in a directory.

#!/bin/bash

# For loop to iterate over each file in the current directory
for file in $(ls)
do
    echo "File: $file"
done

Explanation:

  1. Command Substitution: $(ls) executes the ls command, listing all files in the current directory.
  2. For Loop: Iterates over each file name returned by ls.
  3. Echo Statement: Prints “File: [File Name]” for each file.

Output:

File: document.txt
File: script.sh
File: image.png
...

Note: Using ls in scripts can sometimes lead to issues with file names containing spaces or special characters. For more robust scripts, consider using globbing (e.g., for file in *).


Example 4: Looping Through Files with a Specific Extension

Suppose you want to perform an action on all .txt files in a directory.

#!/bin/bash

# For loop to iterate over all .txt files
for file in *.txt
do
    echo "Processing $file..."
    # Example command: Display the first line of each file
    head -n 1 "$file"
done

Explanation:

  1. Globbing: *.txt matches all files ending with .txt in the current directory.
  2. For Loop: Iterates over each .txt file.
  3. Echo Statement: Prints “Processing [File Name]…”.
  4. Head Command: Displays the first line of each file.

Sample Output:

Processing notes.txt...
Welcome to my notes.
Processing report.txt...
Executive Summary
Processing data.txt...
ID, Name, Age

Example 5: Nested For Loops

Sometimes, you may need to use a for loop within another for loop. For example, iterating over a list of directories and then over files within each directory.

#!/bin/bash

# Define a list of directories
directories="Documents Downloads Pictures"

# Outer loop: Iterate over each directory
for dir in $directories
do
    echo "Directory: $dir"

    # Inner loop: Iterate over each file in the directory
    for file in "$dir"/*
    do
        echo "  File: $(basename "$file")"
    done
done

Explanation:

  1. Outer Loop: Iterates over each directory in the directories list.
  2. Echo Statement: Prints the directory name.
  3. Inner Loop: Iterates over each file within the current directory.
  4. Echo Statement: Prints the file name, indented for clarity.

Sample Output:

Directory: Documents
  File: resume.pdf
  File: project.docx
Directory: Downloads
  File: setup.exe
  File: movie.mkv
Directory: Pictures
  File: photo1.jpg
  File: photo2.png

Common Mistakes to Avoid

  1. Missing done: Always end your for loop with done. Forgetting this will result in a syntax error.
   for i in {1..3}
   do
       echo "Number: $i"
   # Missing 'done' here
  1. Incorrect Variable Usage: Variables inside the loop should be referenced with a $.
   for i in {1..3}
   do
       echo "Number: $i"  # Correct
       echo "Number: i"   # Incorrect, prints 'i' literally
   done
  1. Spaces Around = in Variable Assignment: When assigning values to variables, avoid spaces around =.
   name="John"    # Correct
   name = "John"  # Incorrect
  1. Using Quotes Properly: When dealing with filenames or strings that may contain spaces, use quotes to prevent word splitting.
   for file in *.txt
   do
       echo "Processing '$file'"
   done

Tips for Effective Use of For Loops

  • Use Meaningful Variable Names: Choose variable names that clearly indicate what they represent.
  for filename in *.log
  do
      echo "Archiving $filename"
  done
  • Combine With Other Control Structures: For loops can be combined with if statements, case statements, and other loops for more complex scripts.
  for file in *.sh
  do
      if [[ -x "$file" ]]; then
          echo "$file is executable."
      else
          echo "$file is not executable."
      fi
  done
  • Use Brace Expansion for Simple Ranges: When iterating over a simple numeric range, brace expansion is concise and efficient.
  for i in {10..1..-1}
  do
      echo "Countdown: $i"
  done
  • Leverage Command Substitution Carefully: Be cautious when using command substitution to avoid unexpected word splitting. Use quotes when necessary.
  for user in "$(cut -d: -f1 /etc/passwd)"
  do
      echo "User: $user"
  done

Note: The above example might not work as intended due to word splitting. Instead, use a while loop with read for safer handling.


Conclusion

Bash for loops are essential for automating repetitive tasks and managing data efficiently in shell scripts. By understanding the basic syntax and practicing with simple examples, you can leverage for loops to enhance your scripting skills. Remember to pay attention to syntax details and practice writing your own loops to become more comfortable with their usage.


Practice Exercise

Task: Write a Bash script using a for loop that creates backup copies of all .conf files in the current directory by appending .bak to each filename.

Example:

  • Original file: settings.conf
  • Backup file: settings.conf.bak

Solution:

#!/bin/bash

# Iterate over all .conf files
for file in *.conf
do
    # Create a backup by copying the file with .bak extension
    cp "$file" "$file.bak"
    echo "Backup created for $file as $file.bak"
done

Explanation:

  1. Loop Through .conf Files: The loop goes through each file ending with .conf.
  2. Copy Command: cp creates a copy of the file with .bak appended to its name.
  3. Echo Statement: Confirms the creation of each backup.

Running the Script:

Save the script as backup.sh, make it executable, and run it:

chmod +x backup.sh
./backup.sh

Expected Output:

Backup created for settings.conf as settings.conf.bak
Backup created for database.conf as database.conf.bak
...