Sunday 5 April 2020

bash ranges

This is not widely known, although it is adequately documented in the bash(1) man page thus:

A sequence expression takes the form {x..y[..incr]}, where x and y are either integers or single characters, and incr, an optional increment, is an integer. When integers are supplied, the expression expands to each number between x and y, inclusive. Supplied integers may be prefixed with 0 to force each term to have the same width. When either x or y begins with a zero, the shell attempts to force all generated terms to contain the same number of digits, zero-padding where necessary. When characters are supplied, the expression expands to each character lexicographically between x and y, inclusive, using the default C locale. Note that both x and y must be of the same type. When the increment is supplied, it is used as the difference between each term. The default increment is 1 or -1 as appropriate.

This means that you can expect these expressions to work:

$ echo {0..10}
0 1 2 3 4 5 6 7 8 9 10
$ echo {z..a}
z y x w v u t s r q p o n m l k j i h g f e d c b a
$ echo {01..20..2}

01 03 05 07 09 11 13 15 17 19
$ echo f{20..01..2}

f20 f18 f16 f14 f12 f10 f08 f06 f04 f02

In the last case, notice a prefix was prepended as you would expect. Suffixes work too, of course. -2 will also work. The direction is determined by the range.

Thus {01..20} is a more efficient alternative to using

$(seq -w 01 20)

Brace expansion happens early so no use storing the expression in a variable or having one of the start, end, or increment a variable.

In case you are still wondering what ranges are useful for, a typical use is in a for loop:
for month in {01..12}
do
...
done

No comments:

Post a Comment