## 28.4. Build Strings with { }

I've been finding more and more uses for the `{}` pattern-expansion characters in csh , tcsh, zsh, and bash. They're similar to *, ?, and [ ] (Section 33.2), but they don't match filenames the way that `*`, `?`, and `[ ]` do. You can give them arbitrary text (not just filenames) to expand -- that "expand-anything" ability is what makes them so useful.

Here are some examples to get you thinking:

- To fix a typo in a filename (change fixbold5.c fixbold6.c):

  >     % mv fixbold{5,6}.c

  To see what the shell will do with `{}`, add echo (Section 27.5) before the mv:

  >     % echo mv fixbold{5,6}.c
  >     mv fixbold5.c fixbold6.c

- To copy filename to filename.bak without retyping filename:

  >     % cp filename{,.bak}

- To print files from other directory(s) without retyping the whole pathname:

  >     % lpr /usr3/hannah/training/{ed,vi,mail}/lab.{ms,out}

  That would give lpr (Section 45.2) all of these files:

  >     /usr3/hannah/training/ed/lab.ms
  >     /usr3/hannah/training/ed/lab.out
  >     /usr3/hannah/training/vi/lab.ms
  >     /usr3/hannah/training/vi/lab.out
  >     /usr3/hannah/training/mail/lab.ms
  >     /usr3/hannah/training/mail/lab.out

  ...in one fell swoop!

- To edit ten new files that don't exist yet:

  >     % vi /usr/foo/file{a,b,c,d,e,f,g,h,i,j}

  That would make /usr/foo/filea, /usr/foo/fileb, ... /usr/foo/filej. Because the files don't exist before the command starts, the wildcard `vi` `/usr/foo/file[a-j]` would not work (Section 28.3).

- An easy way to step through three-digit numbers 000, 001, ..., 009, 010, 011, ..., 099, 100, 101, ... 299 in the C shell is:

  `foreach` Section 28.9

  >     foreach n ({0,1,2}{0,1,2,3,4,5,6,7,8,9}{0,1,2,3,4,5,6,7,8,9})
  >        ...Do whatever with the number $n...
  >     end

  Yes, csh also has built-in arithmetic, but its `@` operator can't make numbers with leading zeros. This nice trick shows that the `{}` operators are good for more than just filenames.

- In zsh, `{}` also understands `..` as an integer-range operator. So you could generate the 300 numbers in the previous example with `{000..299}`. The leading `00` tells zsh to pad all output numbers to three digits with leading zeros.

  If you give the range in reverse order, like `{299..0}`, zsh will output the integers in descending order: 299, 298, and so on, down to 1 and 0.

- To send a mail (Section 1.21) message to multiple recipients where a part of each email address is repeated:

  >     % mail -s "Link to me" webmaster@{foo,bar,baz}.com < msgfile

- If you're using a graphical email program (not the command-line mail program shown above), and you're sending an email message to lots of people at the same host, it can be a pain to type the same hostname over and over in the "To:" line. Let the shell's `{}` operators do the dirty work! Use echo to output the addresses. (Note the comma (,) after each address.) Then copy all of them -- except the final comma -- with your mouse, and paste them into the GUI mail program:

  >     % echo {jane,joe,jill,john,jean}@foo.org,
  >     jane@foo.org, joe@foo.org, jill@foo.org, john@foo.org, jean@foo.org,

- To create sets of subdirectories:

  >     % mkdir man
  >     % mkdir man/{man,cat}{1,2,3,4,5,6,7,8}
  >     % ls -F man
  >     cat1/   cat3/   cat5/   cat7/   man1/   man3/   man5/   man7/
  >     cat2/   cat4/   cat6/   cat8/   man2/   man4/   man6/   man8/

- Here's how to copy the remote files file1.c, file12.c, file45.c, and file77.c from the subdirectory foo on the remote host remulac to the local system. Your local shell expands the strings (into `remulac:foo/file1.c`, `remulac:foo/file12.c`, etc.) and passes them to scp (Section 29.14):

  `.` Section 1.16

  >     % scp remulac:foo/file{1,12,45,77}.c .

- Here are two ways to print 10 copies of the file project_report if your lpr (Section 45.2) command doesn't have a -#10 option. We showed the first way in the first two editions of this book. Dimi Shahbaz sent us the second one: 9 commas give 10 filenames. (Thanks, Dimi!) Both of them work on all the shells I tried:

  >     % lpr project_repor{t,t,t,t,t,t,t,t,t,t}
  >     % lpr project_report{,,,,,,,,,}

  Of course, this doesn't just work for lpr or filenames. Remember that the shell expands the list of strings, so you can use these tricks anywhere you use `{}`.

In bash, the complete-into-braces editor command (which is bound to the `M-{` key sequence by default in Emacs mode) expands a string into a list of matching filenames in braces. For example:

>     $ ls pr*
>     prog1.c   prog2.c   program1.c   program2.c
>     $ cc pr META{
>     $ cc pr{og1.c,og2.c,ogram1.c,orgram2.c}

Then you can edit the brace expression.

-- JP

Copyright © 2003 O'Reilly & Associates. All rights reserved.