59

I understand what brace expansion is, but I don't know how best to use it.

When do you use it?
Please teach me some convenient and remarkable examples if you have your own tip.

Wouter Beek
  • 241
  • 1
  • 2
  • 6
Benjamin
  • 1,505
  • 2
  • 18
  • 25
  • For the record, `{a,b}` brace expansion was first introduced in csh in the late 70s and the `{1..10}` `{001..100}` `{a-z}` variant by zsh in the early 90s, and yet more variations in ksh93 in the mid 2000s. Beside the shells you've already tagged, it's also available in fish and yash. – Stéphane Chazelas Jun 22 '22 at 19:10

7 Answers7

60

Brace expansion is very useful if you have long path names. I use it as a quick way to backup a file:

cp /a/really/long/path/to/some/file.txt{,.bak}

will copy /a/really/long/path/to/some/file.txt to /a/really/long/path/to/some/file.txt.bak

You can also use it in a sequence. I once did so to download lots of pages from the web:

wget http://domain.example/book/page{1..5}.html

or

for i in {1..100}
do
   #do something 100 times
done
Stephen Ostermiller
  • 982
  • 2
  • 11
  • 27
dogbane
  • 29,087
  • 16
  • 80
  • 60
  • 9
    This can be used for argument duplication as well. Say you have some program which requires a '-f' argument for every file to operate on. instead of doing `program -f file1 -f file2 -f file3`, you can do `program "-f file"{1..3}` – phemmer Feb 01 '11 at 20:42
  • This is a shame. I just discovered it but do the backup thing on extra-long paths for years without knowing rhis. Thanks. – smonff May 20 '14 at 12:41
  • 2
    @Patrick: That fails because `program` gets three words: `"-f file1" "-f file2" "-f file3"`, instead of 6: `"-f" "file1" "-f" "file2" "-f" "file3"`. – musiphil May 18 '15 at 18:52
  • 1
    @dogbane: Using expansion for use in a `for` loop is a bit pointless, since you can write `for ((i=1; i<=100; i++))` and it is more efficient. – musiphil May 18 '15 at 18:54
37

Brace expansion comes very handy when creating large directory structures:

mkdir -p dir1/{subdir1,subdir2}/{subsubdir1,subsubdir2}

This will give you

find dir1 -type d
dir1
dir1/subdir1
dir1/subdir1/subsubdir1
dir1/subdir1/subsubdir2
dir1/subdir2
dir1/subdir2/subsubdir1
dir1/subdir2/subsubdir2

You could even go one step further and put brace expansion into brace expansion:

mkdir -p dir1/{subdir{1,2}}/{subsubdir{1,2}}

This will give you the same directory structure as the example above.

Christian
  • 1,571
  • 9
  • 10
  • 3
    Nesting is nice, but your nesting example (`mkdir -p dir1/{subdir{1,2}}/{subsubdir{1,2}}`) doesn't actually serve any purpose. You could have just done this: `mkdir -p dir1/subdir{1,2}/subsubdir{1,2}`. – iconoclast Jul 14 '11 at 18:40
  • @iconoclast, it does serve a purpose if you interpret `subdir1` and `subdir2` in the non-literal sense. Replace `subdir1` with `cat` and `subdir2` with `dog` for example. – ephsmith Jul 26 '12 at 10:55
  • 2
    @ephsmith: if you interpret "subdir1" as standing in for "cat" and "subdir2" for "dog", then the nesting example fails, since it uses subdir{1,2}, and there is no string that you can replace "subdir" with that will make subdir{1,2} return {cat,dog}. – iconoclast Jul 26 '12 at 21:04
23

I use it when I want to reduce typing:

geany /path/to/file1 /path/to/file2
# versus
geany /path/to/file{1,2}

Another example:

wajig install libpam0g-dev libiw-dev libdb-dev
# versus
wajig install lib{pam0g,iw,db}-dev
tshepang
  • 64,472
  • 86
  • 223
  • 290
13

I use it to compare actual test output to desired test output during development. If test #41 fails, it's easy to see what the difference between the test output (in file tests.output/041) and the desired output (in file tests.out/041):

$ diff tests.{out,output}/041
12

Some frequent cases for me are:

For renaming:

mv myText.{txt,tex}

or

mv myText.tex{,.old}

or

cp myText.tex{,.backup}

(Although it's less messy to use version control for the last 2 tasks.)

For comparing (already mentioned):

diff path{1,2}/a.txt
imz -- Ivan Zakharyaschev
  • 15,113
  • 15
  • 61
  • 123
4

There are several great answers here, but none of them mention when not to use brace expansion. Like the other answerers, I use brace expansion on the command line quite a bit. I also use it in my aliases and functions since I can expect a smart shell.

I do not use it in my shell scripts (unless there's some other reason the scripts should be bash or zsh, though in those cases, it's best to upgrade to a "real" scripting language like perl or python). Brace expansion is not portable since it is not in the POSIX shell standard. Even if it works in your /bin/sh-shebanged shell scripts, it will not work on systems with more stripped /bin/sh shells (e.g. dash).

In the case of a difference of a single digit, you don't need brace expansion; a character class will suffice:

Bashism:

diff file{1,2}

Portable:

diff file[12]
Adam Katz
  • 3,800
  • 1
  • 24
  • 33
  • 6
    A difference is that `file{1,2}` will always expand to `file1 file2`, while `file[12]` expands only to existing filenames: i.e. if `file1` exists but `file2` doesn't, `file[12]` expands to `file1` only. The `[]` expansion is really a restricted version of `?` expansion (and they are called "pathname expansions"). – musiphil May 18 '15 at 18:57
  • Correct, brace expansion is not [shell globbing](https://en.wikipedia.org/wiki/Glob_%28programming%29) (a.k.a. pathname expansion). That's a good call-out that hasn't really been mentioned yet: brace expansion is better at noting unexpectedly absent paths. You can also glob inside brace expansion. – Adam Katz May 18 '15 at 21:28
2

After splitting a very big file with

split -b 100m hugeFile.zip part.

let's suppose it splitted into 262 pieces, in other words part.aa,part.ab,part.ac ... part.kb

Your can join those pieces again by nesting brace expansions, like this

cat part.{{a..j}{a..z},k{a..b}} > hugeFile.zip
Madacol
  • 131
  • 3