In bash
I can use curly braces to pattern match several files, e.g.
ls *.{dot,svg,err}
If there's no file for a particular extension, I get a warning, but the remaining files will be listed.
ls: cannot access '*.err': No such file or directory
However, in zsh
I get an error instead and no output is produced for the existing files.
zsh: no matches found: *.err
This is also applies for removing, where attempting to remove files with this:
rm -f *.{dot,svg,err}
Will remove all matching files in bash
without any error or warning,
but in zsh
it will err out and not remove anything at all.
Is there a way to make zsh
behave in the same way as bash
, or is there another way to remove/list the existing files with similar ease¹?
¹Obviously I can do something like find . -name '*.dot' -or -name '*.svg' -or -name '.err' | xargs rm
but that's not particularly easy/practical.
Best Answer
You don't get a warning in
bash
, you get an error byls
(you'll find thatls
exit status is non-0 which indicates it has failed).In both
zsh
andbash
,{...}
is not a globbing operator, it's an expansion that occurs before globbing.In:
(you forgot the
-d
and--
btw), the shell expands the{...}
first:and then does the glob.
bash
like most Bourne-like shells has that misfeature that non-matching globs are passed as-is. While onzsh
, a non-matching glob is an error.See how
rm -f [ab].c
inbash
could delete the[ab].c
file if there was no file calleda.c
norb.c
. Inzsh
, you'd get a no match error instead. See thefailglob
option inbash
to get a similar behaviour.in
zsh
would enable thenullglob
option on all 3 globs, so that if the globs don't match, they are removed, but that's probably not what you want, because if none of the globs match any file, the command will become:Which will list
.
(the current directory) instead.Best here is to use one glob that matches files with either of the 3 extensions:
That will give a sorted list of files to
ls
,ls
will be run unless there's no file found matching that one pattern.You also have the option to enable the
sh
/bash
(bogus IMO) behaviour withemulate sh
or withunsetopt nomatch
. A slightly better approach is to enable thecsh
behaviour (which was also the behaviour of Unix shells before the Bourne shell was released):With that option, the command is cancelled only if all the globs on the command line fail to match. If at least one matches, all the ones that don't match are removed so:
Will expand the
dot
,svg
anderr
in turn, omitting the missing ones.If you want to compare the effect on the order of the arguments of the different approaches, you need a command that (contrary to
ls
) doesn't sort them before displaying. With GNUls
, you can pass the-U
option for that, or sincels
does only print its arguments here, just useprintf '%s\n' *...
instead.