I knew about this neat shell expansion feature (very helpful for file selection):
1
2
$ echo { foo,ba{ r,z}}
foo bar baz
Today I stumbled upon this stackoverflow answer containing the command (shortened here):
1
$ sudo rsync -avAX --delete --exclude={ "/dev/*" ,"/proc/*" ,"/sys/*" } / /mnt/rootfs
I wondered how it would work since I thought it would expand to … --exclude="/dev/*" "/proc/*" "/sys/*" …
, which wouldn’t exclude those other paths in rsync
.
Turns out my understanding was incomplete:
1
2
$ echo --exclude={ foo,ba{ r,z}}
--exclude= foo --exclude= bar --exclude= baz
It prepends --exclude=
to every expanded, space-separated value! The same is applicable to suffixes too:
1
2
$ echo foo{ 0 ,1} bar
foo0bar foo1bar
As usual, this works for prefixes and suffixes up to a space, unless the space is escaped:
1
2
3
4
$ echo before\ foo{ 0 ,1} bar after
before foo0bar before foo1bar after
$ echo "before foo" { 0 ,1} bar after
before foo0bar before foo1bar after
This feature is called “brace expansion”. And zsh
’s manual does show this use case in the manual: https://zsh.sourceforge.io/Doc/Release/Expansion.html#Brace-Expansion . It also works in bash
: https://mywiki.wooledge.org/BraceExpansion .
/me murmuring to myself: “RTFM ”