Mastering the seq Command: Sequence Generation in Linux

The seq command in Linux is used to generate sequences of numbers.

If you want to produce a simple incremental list or a complex sequence with specific formatting, seq can do that. Let’s dive deep and understand its powerful features.

Generating a sequence from 1 to a specified number

You can use seq command to generate a list of consecutive numbers starting from 1 up to a given limit.
Here’s an example:

\$ seq 5
1
2
3
4
5

By providing the seq command with a single value of 5, it outputs a series of numbers from 1 through 5.

Generating a sequence between two numbers

Also, seq command can generate a sequence between two numbers like this:

\$ seq 3 7
3
4
5
6
7

In this example, we specified both a starting and an ending number. The seq command then provides a series beginning at 3 and ending at 7.

Specifying an Increment

You can also define increments to customize the generated sequences further.
Let’s see a couple of examples:

Positive step

\$ seq 2 2 10
2
4
6
8
10

Here, you’ve set an increment of 2. So, the sequence starts at 2 and jumps in steps of 2 until reaching the final number, which is 10.

Negative step

Now, let’s see how to count backwards using a negative step:

\$ seq 5 -1 1
5
4
3
2
1

In this case, we begin at 5 and decrement by 1 until we reach the specified end number, which is 1.

Formatting Output

The seq command isn’t just about generating raw numbers. It allows you to format the output with precision, ensuring the sequence appears just how you need it.

This can be useful for tasks requiring formatted numerical sequences.
Let’s see the -f option in action:

\$ seq -f "%.2f" 1 3
1.00
2.00
3.00

By using %.2f as the format specifier, the numbers are presented with two decimal places.

This is ideal for representing monetary values, measurements, and other scenarios requiring precision.
How about when you need numbers padded with zeros?

\$ seq -f "%04g" 7 10
0007
0008
0009
0010

Here, %04g ensures each number has a total width of 4 characters, padding with zeros where necessary.

Separator Between Numbers

You can use the -s option to set the separator between the generated list.

\$ seq -s, 1 3
1,2,3

The numbers are separated by commas instead of the default newline.
Need numbers separated by spaces?

\$ seq -s" " 1 3
1 2 3

Simply place a space between the quotation marks after the -s flag, and the sequence will present numbers spaced out.

Equal Width Numbers (Padding)

You can use the -w option to maintain a consistent width by padding them with leading zeros.

\$ seq -w 008 10
008
009
010

Using -w and starting with 008, the sequence maintains a width of three characters, ensuring that all numbers align perfectly.

Using seq in Shell Scripts

Integrating seq within shell scripts can enhance the functionality of loops and offer dynamic ways to manipulate and use sequences.
Here’s a basic example of how you can use seq within a shell script:

#!/bin/bash
for i in \$(seq 1 5); do
echo "Processing item \$i"
done

When this script runs, it will produce:

Processing item 1
Processing item 2
Processing item 3
Processing item 4
Processing item 5

When to use seq vs. other methods

In shell scripting, there are various ways to create loops, using seq is one of them.

Choosing between seq and other constructs depends on the exact requirements of the task.
For simple, numeric-based for loops:

for i in \$(seq 1 3); do
echo \$i
done

However, in modern Bash versions, brace expansion offers a more native approach:

for i in {1..3}; do
echo \$i
done

Brace expansion is quick and efficient for straightforward sequences, while seq shines in scenarios that require specific increments or formatted outputs.

Performance comparison with other methods

Let’s benchmark the performance of each method.

We’ll do the following:

Use the time command to measure the time taken by the seq command to generate a sequence of numbers.

Use the time command to measure the time taken by brace expansion to generate the same sequence of numbers.

Here’s how we can measure the performance for generating a sequence of numbers from 1 to 1,000,000:

time seq 1 1000000 > /dev/null

For seq:

Output:

real 0m0.015s
user 0m0.010s
sys 0m0.004s

For brace expansion:

time echo {1..1000000} > /dev/null

Output:

real 0m0.753s
user 0m0.725s
sys 0m0.027s

seq is more efficient, especially for larger sequences. If performance is a concern, it would be advisable to use the seq command over brace expansion.