Brace Expansion (Linux)


To totally unlock this section you need to Log-in


Login

Brace expansion is a mechanism by which arbitrary strings may be generated. Patterns to be brace expanded take the form of an optional preamble, followed by either a series of comma-separated strings or a sequence expression between a pair of braces, followed by an optional postscript.

The preamble is prefixed to each string contained within the braces, and the postscript is then appended to each resulting string, expanding left to right.

Brace expansions may be nested. The results of each expanded string are not sorted; left to right order is preserved. For example:

bash$ echo a{d,c,b}e
ade ace abe

The above echo statement avoids you to specifying the three characters separately, by constructing three other strings composed by the preamble, the character and the postscript.

String lists

{string1,string2,...,stringN}

Without the optional preamble and postscript strings, the result is just a space-separated list of the given strings:

$ echo {I,want,my,money,back}
I want my money back

With preamble or postscript strings, the result is a space-separated list of all possible combinations of preamble, specified strings and postscript:

$ echo _{I,want,my,money,back}
_I _want _my _money _back

$ echo {I,want,my,money,back}_ I_ want_ my_ money_ back_
$ echo _{I,want,my,money,back}- _I- _want- _my- _money- _back-

The brace expansion is only performed, if the given string list is really a list of strings, i.e. if there's minimum one "," (comma)! Something like {money} doesn't expand to something special, it's really only the text "{money}".

1. Example for Backup using brace expansion

$ cat bkup.sh
set -x # expand the commands
da=`date +%F`
cp $da.log{,.bak}

$ ./bkup.sh ++ date +%F + da=2010-05-28 + cp 2010-05-28.log 2010-05-28.log.bak

In the above backup script, it copies the current date log file with the extension .bak. The first element is empty in the braces, so first element will have only preamble.

2. Example for Restore using brace expansion

$ cat restore.sh
set -x # expand the commands
da=`date +%F`
cp $da.log{.bak,}

$ ./restore.sh ++ date +%F + da=2010-05-28 + cp 2010-05-28.log.bak 2010-05-28.log

In the restore script, the first element in the parameter is .bak where as second element is empty.

3. Example for Brace Expansion without preamble and postscript

If there is no preamble and postscript, it just expands the elements given in the braces.

$ cat expand.sh
echo {oct,hex,dec,bin}

$ ./expand.sh oct hex dec bin

Without the optional preamble and postscript strings, the result is just a space separated list of the given strings.

Ranges

{..}

Brace expansion using ranges is written giving the startpoint and the endpoint of the range. This is a "sequence expression". The sequences can be of two types:

  • Integers (optionally zero padded, optionally with a given increment).
  • Characters.
$ echo {5..12}
5 6 7 8 9 10 11 12

$ echo {c..k} c d e f g h i j k

When you mix these both types, brace expansion is not performed:

$ echo {5..k}
{5..k}

When you zeropad one of the numbers (or both) in a range, then the generated range is zeropadded, too:

$ echo {01..10}
01 02 03 04 05 06 07 08 09 10

Similar to the expansion using stringlists, you can add preamble and postscript strings:

$ echo 1.{0..9}
1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9

$ echo ---{A..E}--- ---A--- ---B--- ---C--- ---D--- ---E---

4. Example for Integer and character sequences

$ cat sequence.sh
cat /var/log/messages.{1..3}
echo {a..f}{1..9}.txt

$ ./sequence.sh May 9 01:18:29 x3 ntpd[2413]: time reset -0.132703 s May 9 01:22:38 x3 ntpd[2413]: synchronized to LOCAL(0), stratum 10 May 9 01:23:44 x3 ntpd[2413]: synchronized to May 9 01:47:48 x3 dhclient: DHCPREQUEST on eth0 May 9 01:47:48 x3 dhclient: DHCPACK from 23.42.38.201 .. .. a1.txt a2.txt a3.txt a4.txt b1.txt b2.txt b3.txt b4.txt c1.txt c2.txt c3.txt c4.txt

The first cat command, expands messages.1,messages.2 and messages.3 and displays the content. and in the next echo statement character and integer sequences are combined and used.

Sequences with increment value

In kshell brace expansion, you can use increment value, to generate the sequences.

<start>..<end>..<incr>

incr is numeric. You can use a negative integer, but the correct sign is deduced from the order of start and end.

5. Example for using Increment in sequences

$ ksh
$ echo /var/log/messages.{1..7..2}
/var/log/messages.1 /var/log/messages.3 /var/log/messages.5 /var/log/messages.7
$

Using this you could see the alternate days logfiles.

Pitfall in Brace expansion

Brace expansion does not expand bash variables, because the brace expansion is the very first step of the shell expansion, variable will be expanded later.

6. Example for Variables in expansion

If you see the output of the following two for statement, you could identify the above pitfall.

$ cat var_seq.sh
# Print 1 to 4 using sequences.
for i in {1..4}
do
        echo $i
done
start=1
end=4

# Print 1 to 4 using through variables echo "Sequences expressed using variables" for i in {$start..$end} do echo $i done
$ ./var_seq.sh 1 2 3 4
Sequences expressed using variables {1..4}

Common use and examples

Massdownload: in this example, wget is used to download documentation that is split over several numbered webpages. wget won't see your braces. It will see 6 different URLs to download.

wget http://docs.example.com/documentation/slides_part{1,2,3,4,5,6}.html

Of course it's possible, and even easier, to do that with a sequence:

wget http://docs.example.com/documentation/slides_part{1..6}.html

Generate a subdirectory structure: your life is hard? Let's ease it a bit - that's what shells are here for.

mkdir /home/bash/test/{foo,bar,baz,cat,dog}

Generate numbers with a prefix 001 002...using a prefix:

for i in 0{1..9} 10; do printf "%s\n" "$i";done

If you need to create words with the number embedded, you can use nested brace:

printf "%s\n" img{00{1..9},0{10..99},{100..999}}.png

Formatting the numbers with printf:

echo $(printf "img%02d.png " {1..99})

Repeating arguments or words:

somecommand -v -v -v -v -v

Can be written as:

somecommand -v{,,,,}

Which is a kind of a hack, but hey, it works.