Nested for Loop in Bash

Abdul Mateen Oct 08, 2023
  1. Variations of for Loop in Bash
  2. Nested for Loop in Bash
Nested for Loop in Bash

In this tutorial, we will discuss nested loops in bash. First, we will quickly discuss the different available for loop formulations in bash. Next, we will discuss the nested for loop with examples.

Variations of for Loop in Bash

First of all, let’s look at the syntax of the for loop in bash:

for var in something
do
    command
done

In this syntax, the variable name is the user’s choice. There are multiple options for something, which we will discuss shortly.

We can write any number of commands inside the for body. Multiple for loop variations are available in bash; we will quickly see some below.

for in the Range of Numbers

We can specify a list of numbers with a for loop and can iterate on those numbers one by one, as depicted by the following example:

for i in 1 3 8
do
    echo $i
done

The loop will iterate on the given list of values (i.e., 1 3 8). In this particular example, the output will be:

1
3
8

for in List of Values

We can define a list of values and iterate over the list as follows:

x=(1 3 8)
for i in ${x[@]}
do
    echo $i
done

The outcome of this code will be the same as the output of the previous example. In the for loop statement, the {x[@]} represents: for every element of list x.

for in the Range of a Sequence

We can give a range of values with starting number, followed by a double dot (..), followed by an ending number. Similarly, we can put another pair of dots followed by a step.

For example, let’s look at the following two example loop formulations:

for i in {1..3}
do
    echo $i
done
echo "----------------------"
for i in {1..3..2}
do
    echo $i
done

The output of this code will be:

1
2
3
----------------------
1
3

for in String With Words

We can define a list of words in a string separated by spaces and iterate over the words in the string as follows:

names="Asim Babar Munir Ali"
for name in $names
do
    echo $name
done

The output of this code will be given names in separate lines as follows.

Asim
Babar
Munir
Ali

C-Style for Expression

We can give an expression in the for loop similar to the for in C language. See the example:

for ((i=1;i<=5;i++))
do
    echo $i
done

It will produce the following output:

1
2
3
4
5

Use of continue Statement in for Loop

We can put some conditions in the body of the for loop, followed by a continue statement to skip the next body of the loop. See the example:

for ((i=1;i<=5;i++))
do
    if [ $i == 3 ]
    then
        continue
    fi
    echo $i
done

Due to the if condition, the loop will skip the echo command for value 3; therefore, the output will be: 1 2 4 5.

Loop Over Command Line Arguments

We can give command line arguments to our bash script and run a for loop over the arguments separated by spaces. See the example:

for i in $@
do
    echo "Script arg is $i"
done

In the first line, the $@ symbol represents a list of arguments separated by spaces. See the output for this example:

bash myscript.sh 13 28
Script arg is 13
Script arg is 28

Loop Over Output of Command

We can run the for loop over the output of some command. See the example:

for f in $(ls)
do
  echo "**** $f *****"
done

This script will take the output of the ls command and iterate over the values. See example output:

**** first.c *****
**** second.c *****
**** third.c *****

Loop Over Variable Sequence

We can also run some input based on some variable at run time. For this, we can use seq 1 1 $n, where n can be a variable. See the example:

n=4
for i in $(seq 1 1 $n)
do
    echo -n $i
    echo " "
done

Here, I have assigned the value 4 to a variable, whereas it can be some count, like word count etc. See example output:

1
2
3
4

Nested for Loop in Bash

We have a variety of nested for loops in bash. According to our requirement, we can create several variations of the nested for loops (i.e., by combining the available for loop formulations.

Here, we will see multiple examples with the output:

  • for number in {1..5}
    do
    	for n in {1..10}
    	do
    		echo -n $((number*$n))
    		echo -n " "
    	done
    	echo ""
    done
    

    The output of this code is:

    1 2 3 4 5 6 7 8 9 10
    2 4 6 8 10 12 14 16 18 20
    3 6 9 12 15 18 21 24 27 30
    4 8 12 16 20 24 28 32 36 40
    5 10 15 20 25 30 35 40 45 50
    
  • for number in 2 5 9
    do
    	for n in {1..10}
    	do
    		echo -n $((number*$n))
    		echo -n " "
    	done
    	echo ""
    done
    

    The output of this code is:

    2 4 6 8 10 12 14 16 18 20
    5 10 15 20 25 30 35 40 45 50
    9 18 27 36 45 54 63 72 81 90
    
  • for number in {1..5}
    do
    	for n in $(seq 1 1 $number)
    	do
    		echo -n $n
    	done
    	echo ""
    done
    

    The output of this code is:

    1
    12
    123
    1234
    12345
    

    We may get several lines from the command line argument to print a variable-size pattern. See code:

    for number in $(seq 1 1 $@)
    do
    	for n in $(seq 1 1 $number)
    	do
    		echo -n $n
    	done
    	echo ""
    done
    

    The output of the command bash pattern2.sh 6 is:

    1
    12
    123
    1234
    12345
    123456
    

    Where patter2.sh is the name of this script and 6 is the command line argument.

  • for number in $(seq 1 1 $@)
    do
    	for n in $(seq 1 1 $number)
    	do
    		echo -n "*"
    	done
    	echo ""
    done
    

    The output of the code with argument 4 is:

    *
    **
    ***
    ****
    
  • messages="Sea_is_rough Don't_go_too_far_in_the_sea Remain_in_the_group Don't_take_kids_inside"
    for i in 1 2 3 4 5
    do
    	for message in $messages
    	do
    		echo $message
    	done
    	echo "----------------------------------"
    done
    

    The output of this is:

    Sea_is_rough
    Don't_go_too_far_in_the_sea
    Remain_in_the_group
    Don't_take_kids_inside
    ----------------------------------
    Sea_is_rough
    Don't_go_too_far_in_the_sea
    Remain_in_the_group
    Don't_take_kids_inside
    ----------------------------------
    Sea_is_rough
    Don't_go_too_far_in_the_sea
    Remain_in_the_group
    Don't_take_kids_inside
    ----------------------------------
    Sea_is_rough
    Don't_go_too_far_in_the_sea
    Remain_in_the_group
    Don't_take_kids_inside
    ----------------------------------
    Sea_is_rough
    Don't_go_too_far_in_the_sea
    Remain_in_the_group
    Don't_take_kids_inside
    ----------------------------------
    
  • for number in $@
    do
    	for i in $(seq 1 1 $number)
    	do
    		echo -n "$i "
    	done
    	echo ""
    done
    

    The output of this code for Bash counting.sh 4 5 8 is:

    1 2 3 4
    1 2 3 4 5
    1 2 3 4 5 6 7 8
    
  • for number in $(seq 10 1 20)
    do
    	if [[ $number == 11 || $number == 13 || $number == 17 || $number == 19 ]]
    	then
    		continue
    	fi
    	for n in {1..10}
    	do
    		echo -n $((number*$n))
    		echo -n " "
    	done
    	echo ""
    done
    

    The output of this code is:

    10 20 30 40 50 60 70 80 90 100
    12 24 36 48 60 72 84 96 108 120
    14 28 42 56 70 84 98 112 126 140
    15 30 45 60 75 90 105 120 135 150
    16 32 48 64 80 96 112 128 144 160
    18 36 54 72 90 108 126 144 162 180
    20 40 60 80 100 120 140 160 180 200
    

Conclusively, we have a variety of nested for loops in bash. Therefore, we can use combinations of the available for loop variations according to our requirements to complete the task.