The Linux Rain Linux General/Gaming News, Reviews and Tutorials

Building sequences of numbers on the command line

By Bob Mesibov, published 13/01/2015 in Tutorials


There are two easy-to-use tools for generating numerical sequences. 'Brace expansion' is a BASH shell built-in, while the seq command is included in the GNU/Linux 'coreutils' package. Each tool has its peculiarities and advantages, as shown below.

Simple sequences

One difference between the two tools is the form of the output. In the screenshot below I've generated the set of 10 years between from 2005 through 2014, using the {START...END} syntax for brace expansion and seq START END. Both tools default to a numerical increment of 1:

Brace expansion separates its results with a single space, while seq puts each result on a new line. To make the brace expansion into a list, you can pipe it to the tr command:

The seq command can also generate a space-separated sequence. Just specify a single space with the output separator option -s:

Sequences with added fronts and backs

When brace expansion generates its sequence, it can add to each result something at the front (called the preamble) and at the back (postscript), like this:

Making that into a list is do-able by piping the result to an appropriate sed substitution:

The seq command can only add a front and a back to the whole sequence it generates, not to each number in the sequence:

But with the help of a suitable separator, it's possible:

Zero-padded sequences and special characters

Both brace expansion and seq can add leading zeroes to the numbers in a sequence. Brace expansion does it by taking a hint — if you add leading zeroes, brace expansion will build the sequence logically. The example below builds the sequence 1 through 10 as 3-digit numbers, because I started the sequence with '001':

As shown above, seq does just the same, but you need to add the -w option (for 'equal width').

You can make the brace-expanded sequence into a set of longitudes by 'postscripting' each number with the degree symbol, whose escaped UTF-8 code is '\xc2\xb0':

A simple way to add the degree symbol to the seq sequence is afterwards, by substituting the end-of-line with the symbol's character code:

Increments

As shown above, the default increment for both brace expansion and seq is 1. In BASH version 4, you can change the brace expansion increment with the syntax {START..END..INCREMENT}, as shown below. The corresponding seq syntax is START INCREMENT END:

Negative increments, or 'decrements', operate a little differently in the two tools. In both cases you specify a starting and (nominal) finishing number, where the finishing number is smaller than the starting one. Brace expansion understands this as meaning you want a decrement. seq doesn't, and you have to specify the decrement as a negative number:

Killer (dis)advantages

So far it looks like brace expansion and seq work much the same way. Each tool, however, has at least one big advantage over the other. seq's advantage is that sequence instructions can be passed to the command as a variable:

You can't pass instructions as a variable to brace expansion, because in BASH, brace expansion is always done before variable expansion:

And the killer advantages of brace expansion? There are two.

First, unlike seq, brace expansion understands letters:

Second and more impressively, brace expansion can interleave sequences together, like this:

There's no simple way to get those results with seq!

In (my) real world

There are plenty of tutorials on the Web which show practical examples of brace expansion and seq, but to be honest, the only regular use I make of sequences is in building AWK commands.

AWK specifies each field in one of my tab-separated data tables as a number preceded by a dollar sign, so the command for printing, say, the third and sixth fields from the table 'data' would be:

awk 'BEGIN {FS=OFS="\t"} {print $3,$6}' data

Suppose my table has 20 fields, and I want to print all but the 4th, 9th to 11th, and 18th. I do this by generating the full string of 20 fields:

then manually deleting the fields I don't want to print from the string, and pasting the shortened string into the AWK command. Well, it works.

(Notice in that seq command I didn't specify a starting '1'. If you only specify one number, seq assumes that the sequence begins with 1, and that the specified number is the finishing number.)



About the Author

Bob Mesibov is Tasmanian, retired and a keen Linux tinkerer.

Tags: bash shell.scripting tutorial seq braces commandline
blog comments powered by Disqus