How to Use seq With for Loop in Bash

Written by: Linuxopsys   |   Last updated: June 20, 2023

1. Introduction

To generate a pattern of numbers, we have the readily available seq command. This command in conjunction with the loop with the Bash for loop helps to perform a block of operations on each number in the sequence. In this tutorial, we learn how to use seq command with the for loop in Bash.

2. Syntax

The built-in seq command's sole purpose is to generate a sequence of numbers. A Bash for loop can be easily integrated with seq command to iterate through the numbers generated.

Syntax:

for iterator in $(seq START FACTOR END)
do
…
…
…
done

By default, seq generates a sequence of numbers from 1 to LAST with a step size of 1.

START is the first and LAST is the last number in the sequence. FACTOR is the step size by which we increment the START value.

3. Using seq with For Loop in Bash

Let's look into how to generate sequences of numbers, iterate over them in loops, and work with variables.

2.1. seq over a range of numbers

We often take help of the seq command when it comes to using the for loops where we have to deal with a range of numbers that are in some sequence. Let us consider this simple example:

#!/bin/bash
for i in $(seq 1 5)
do
	echo $i
 done
generates a sequence of numbers from 1 to 5 and iterates over each number using a for loop

We are generating numbers from 5 to 10 in sequence using the seq command. This is then used by the for loop to iterate over each number in the sequence. The value of the iterator "i" is displayed on the terminal using the echo command. 

We can notice that we did not provide the FACTOR by which the number has to increment. This is because its default value is 1. To make the loop perform the operation in the reverse fashion, we just change the order inside the seq command and provide the FACTOR as -1. We can consider this example:

#!/bin/bash
for i in $(seq 5 -1 1)
do
	echo $i
 done
showcases the usage of the seq command in reverse order within a Bash script

This will print the numbers in reverse order from 5 to 1 as we have set the FACTOR to -1.

To make the loop increment by a count of two everytime we just need to set the FACTOR to 2:

#!/bin/bash
for i in $(seq 1 2 10)
do
	echo $i
 done
uses a for loop and the seq command to display the odd numbers from 1 to 9.

This will print all the odd numbers between 1 to 9. After printing the first value of the iterator, which is 1, the next value of the iterator gets incremented by 2. Hence, it prints 3. This goes on till 9 after which the value of the iterator becomes 11, exceeding the value 10. Hence, the loop finally terminates.

2.2. seq with variables

When we are developing complex scripts that require iterating over for loops using the seq command, we might find the values be available in the variables. To use those variables directly in the for loop, we need to place that variable in the syntax we saw above. Don’t forget to miss the $ prefix before the variable. 

Example:

#!/bin/bash

START=0
FACTOR=50
END=500
for i in $(seq $START $FACTOR $END)
do
	echo $i
 done
for loop with the seq command to generate and display a sequence of numbers from 0 to 500 with a step size of 5

The seq command generates a sequence of numbers from 0 to 500 in steps of 50. The for loop then iterates over each number in the sequence. The value of the iterator "i" is displayed using the echo command. 

2.3. Working with large numbers

Let us consider this script which uses seq command with large numbers

#!/bin/bash
for i in $(seq 100000000 2 1000000000000)
do
  	echo $i
done

If we run this script, there won't be any errors but the loop won't start either. The problem is in the seq command. $(seq ...) is expanded into a list of words before the loop is executed. As a result our initial command expands to something like:

for i in 100000000 100000001 100000002 # till 1000000000000

This result is much too long, which is what causes the infinite delay in starting the loop.

Let us suppose, we have this script,

#!/bin/bash
for i in $(seq 1000000000000 2 1000000000004)
do
  	echo $i
done

This script will work as expected since it will immediately boil down to:

for i in 1000000000000 1000000000002 1000000000004

Hence, the seq command will be able to expand the numbers for the for loop act upon. 

We saw we cannot use the seq command to iterate over large numbers, say from 100000000 to 1000000000000. But, if we still want to iterate over large numbers, we can achieve that using the traditional C type for loop syntax.

#!/bin/bash
for (( i = 100000000; i <= 1000000000000; i++ )) 
do
	echo $i
done

3. Example Scripts

3.1. Loop over IPs 

We will create a pinger where our script will iterate over a range of IPv4 addresses in sequence. We check the availability of the IP using the ping command. It will redirect the IP to a text file provided it's available. Otherwise, we will send it to a different file, meant for storing failed pings.

#!/bin/bash

START=30
END=50
IPSERIES=20.16.2
for ip in $(seq $START $END)
do
   
    ping -c 1 $IPSERIES.$ip 1>/dev/null 2>&1
    RC=$?
    if [ $RC -eq 0 ]
    then
		echo "Ping successful to $ip" 
		echo "$ip" >> success.txt
    else
		echo "Ping unsuccessful to $ip" 
		echo "$ip" >> fail.txt
    fi
done
series of messages indicating whether the ping was successful or unsuccessful for each IP address in the range of 30 to 50,

1. Our script acts as a ping sweeper. 

2. We have defined the START and END variable to ping a tha range of IP addresses present

3. We have defined the IPv4 series in the variable IPSERIES.

4. We have written a for loop with the seq command to generate numbers from 30 to 50 sequentially.

5. For every iteration, we take the IPSERIES variable and concatenate it with the iterator variable "ip" to develop the needed IPv4 address.

6. We ping this IP using the ping command. We have used the -c flag and passed 1. This means we want to ping that particular IP only once to see if the connection is successful. 

7. We will store the IP addresses that respond to our ICMP requests in the file success.txt.

8. Otherwise, that IP will be sent to the fail.txt, indicating failure to ping. We use the for loop to iterate through a given IP range. 

3.2. Iterate over array elements

Our Bash script will verify the existence of a Linux-based user. We will extract the usernames from the /etc/passwd file. For loop in conjunction with break will verify if the user exists and terminate the loop as soon as it's found. 

#!/bin/bash

cities=("Paris" "London" "Oslo" "Moscow")
for i in $(seq 0 $((${#cities[@]} - 1)))
do
	echo "$i : ${cities[$i]}"
done
list of index numbers and their corresponding city names, where each line displays an index followed by a city name

1. We have created an array of cities containing the elements: "Paris", "London". "Oslo", and "Moscow". 

2. The seq command ensures we use a sequence of numbers from 0 to the last index of the array.

3. The number of elements present in this array gets computed using the #cities[@].

4. Reducing this count by 1 will give us the final element of the array. We do this using ${#fruits[@]} - 1

5. We run the loop and in every iteration, the iterator variable "i" is set to the current index in the sequence. 

6. The element is determined using  ${cities[$i]}. 

7.We output the index along with the element.

SHARE

Comments

Please add comments below to provide the author your ideas, appreciation and feedback.

Leave a Reply

Leave a Comment