zsh, I get a "No match found" message when choosing a pattern that does not fit with
rm and that even when redirecting the output.
# rm * > /dev/zero 2>&1 zsh: no matches found: *
How can I get rid of this message?
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.Sign up to join this community
This behaviour is controlled by several of Zsh's globbing options. By default, if a command line contains a globbing expression which doesn't match anything, Zsh will print the error message you're seeing, and not run the command at all. You can disable this in three different ways:
setopt +o nomatch
will leave globbing expressions which don't match anything as-is, and you'll get an error message from
rm (which you can disable using
-f, although that's a bad idea since it will force removals in other situations where you might not want to);
setopt +o nullglob
will delete patterns which don’t match anything (so they will be effectively ignored);
setopt +o cshnullglob
will delete patterns which don’t match anything, and if all patterns in a command are removed, report an error.
The last two override
nomatch. All these options can be unset with
setopt -o ….
nullglob can be enabled for a single pattern using the
N glob qualifier, e.g.:
rm -f -- *(N)
What would you want it to do instead? Not run
rm at all (1)? Run it with a literal
* argument like in other Bourne-like shells (2)? Run it with no argument at all (3)?
files=(*(N)); (($#files)) && rm -- $files. Or
(rm -- *) 2> /dev/nullbut that would also hide genuine errors by
rmwhich would be silly. You could discard the
zsherror but restore stderr for the
rmcommand though with
(rm -- * 2>&3 3>&-) 3>&2 2> /dev/null
emulate sh -c 'rm -- *' 2> /dev/null. Then like in
zshnow emulated for that single command line, the non-matching
*is passed as-is to
rmcomplains as that
*file doesn't exist. We suppress
rm's stderr as you would do in
shto suppress that error message, but again, that's silly as it would hide genuine errors by
rmas opposed to the error incurred by the misbehaviour of
shpassing a literal
rm -f '*'would not complain about an un-existing
*file though, so you could do
emulate sh -c 'rm -f -- *'
rm -- *(N).
rmwould complain though when not passed any argument, though again, not
rm -f -- *(N).
rm -f is the command you want to use if you want all the files gone and only get an error if files could not be removed or IOW are still there after
rm has returned. You also generally want to use
-f in scripts to avoid the user being prompted under some situations.
rm when the glob doesn't match is wrong. The
sh1 behaviour is wrong. It's harmless for a pattern like
*, but for one like
*.[ch] as-is when it doesn't match could cause the
*.[ch] file to be removed by mistake:
$ ls *.[ch] foo.txt $ zsh -c 'rm *.[ch]' zsh:1: no matches found: *.[ch] $ ls *.[ch] foo.txt $ sh -c 'rm *.[ch]' $ ls foo.txt
Failing with an error is the most sensible thing to do and is what
bash -o failglob and the original Unix shell) does.
And if you want to take care yourself of that special case,
zsh makes it easy with its
(N) glob qualifier (for nullglob) like in case (1) above.
fish (at least in recent version) makes it even easier as its globs are expanded in a nullglob fashion when in arguments to the
set command (the one that assigns variables). So, the equivalent there, would be:
set files * if count $files > /dev/null rm -f -- $files end
See Why is nullglob not default for more details.
1. Strictly speaking it's only
sh since the Bourne shell (since Unix V7 in 1979); earlier versions of
sh (which did call
/etc/glob upon unquoted wildcards which is where the glob name comes from) did behave like
zsh -o cshnullglob, that is
/etc/glob would abort the command if none of the globs had any match (and would suppress the non-matching globs if at least one of them had any match). The behaviour was broken by the Bourne shell.