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):
% 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.