运行“rm *”时如何摆脱“找不到匹配项”

use*_*456 46 zsh wildcards rm

使用zsh,在选择不适合的模式rm时,甚至在重定向输出时,我都会收到“未找到匹配项”消息。

# rm * > /dev/zero 2>&1
  zsh: no matches found: *
Run Code Online (Sandbox Code Playgroud)

我怎样才能摆脱这个消息?

Ste*_*itt 72

此行为由 Zsh 的nomatchoption控制。默认情况下,如果命令行包含不匹配任何内容的 globbing 表达式,Zsh 将打印您看到的错误消息,并且根本不运行该命令。您可以通过运行来禁用它

setopt +o nomatch
Run Code Online (Sandbox Code Playgroud)

然后,不匹配任何内容的通配表达式将保持原样,您将收到一条错误消息rm(您可以禁用 using -f,尽管这是一个坏主意,因为它会在其他情况下强制删除您可能不会想要)。

  • 该行为也由 `nullglob` 和 `cshnullglob` 选项控制。如果设置了 nullglob 并且没有找到匹配的文件,则从参数列表中删除模式而不是生成错误。设置 `cshnullglob` 有类似的效果,除非命令中的所有模式都没有匹配,在这种情况下会报错。注意:设置 `nullglob` 或 `cshnullglob` 会覆盖 `nomatch`。您还可以使用 glob 限定符 `N`:`rm *(N)` 为单个模式设置 `nullglob`。 (8认同)
  • 对于那些不熟悉 zsh 的 glob 限定符的人来说,它们必须位于 glob 模式的**末尾**。例如,“*.sh(N)”,而不是“*(N).sh”。[SO参考](/sf/ask/1897192811/),[手动参考](https://zsh.sourceforge.io/Doc/Release /Expansion.html#Glob 限定符) (5认同)
  • `nomatch` 不太理想,这就是类似 Bourne 的 shell 所做的。如果模式不匹配,它会按原样传递给“rm”(!),“rm”将给出错误,或者更糟糕的是可能会删除像“*.[ch]”这样的模式的错误文件实例! (3认同)

Sté*_*las 15

你希望它做什么?根本不运行rm(1)?*像在其他类似 Bourne 的 shell (2) 中一样使用文字参数运行它?完全不带参数地运行它 (3)?

  1. files=(*(N)); (($#files)) && rm -- $files. 或者,(rm -- *) 2> /dev/null但这也会隐藏真正的错误,rm这将是愚蠢的。您可以丢弃zsh错误,但可以使用以下rm命令恢复命令的stderr(rm -- * 2>&3 3>&-) 3>&2 2> /dev/null
  2. emulate sh -c 'rm -- *' 2> /dev/null. 然后像在shzsh现在模拟为单个命令行中,非匹配*原样传递是rmrm抱怨作为*文件不存在。我们抑制rm的 stderr 就像您在sh抑制该错误消息时所做的那样,但同样,这很愚蠢,因为它会隐藏真正的错误,rm而不是sh将文字传递*rm. rm -f '*'不会抱怨一个不存在的*文件,所以你可以这样做emulate sh -c 'rm -f -- *'
  3. rm -- *(N). rm虽然在没有通过任何参数时会抱怨,但同样,不是rm -f: rm -f -- *(N)

通常,rm -f如果您希望所有文件都消失,并且仅在无法删除文件或rm返回后 IOW 仍然存在时才会出现错误,则是您要使用的命令。您通常还希望-f在脚本中使用以避免在某些情况下提示用户。

在这里,rm当 glob 不匹配时调用是错误的。在sh1层的行为是错误的。对于像这样的模式是无害的*,但是对于像 那样的模式,当它不匹配时按原样*.[ch]传递*.[ch]可能会导致*.[ch]文件被错误删除:

$ 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
Run Code Online (Sandbox Code Playgroud)

与错误而失败是做的最明智的事情,是什么zsh(和fishcshtcshbash -o failglob和原来的Unix shell)一样。

如果您想照顾自己的特殊情况,zsh可以使用它的(N)glob 限定符(对于noglob),就像上面的情况(1)一样。fish(至少在最近的版本中)使它变得更加容易,因为它为命令做了一个隐式的noglobset。所以,那里的等价物是:

set files *
if count $files > /dev/null
  rm -f -- $files
end
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请参阅为什么 nullglob 不是默认值


1 . 严格来说,这只是sh从 Bourne shell 开始(自 1979 年的 Unix V7 以来);的早期版本sh(确实调用/etc/glob了未加引号的通配符,这是glob名称的来源)确实表现得像cshor zsh -o cshnullglob,也就是说,/etc/glob如果没有任何匹配的glob将中止命令(并且至少会抑制不匹配的 glob其中一个有任何匹配)。Bourne shell破坏了这种行为。

  • 我认为他希望从“rm”而不是从 shell 获取错误消息。类似于“rm:无法删除‘*’:没有这样的文件或目录”。 (2认同)
  • @Stephane_Chazelas 正如所写,2 是他没有问过的问题的正确答案:)。 (2认同)
  • @Emmanuel,所有三个人都回答了这个问题:如何摆脱“不匹配”错误。OP 的代码抑制了“rm”错误。当没有匹配的文件时,您可以在其他 shell 中执行此操作来抑制错误,并且这也会导致抑制真正的 rm 错误。我的回答概述了这一点,并希望展示 zsh 行为如何更好。 (2认同)
  • @baggiponte 请注意,“(N)”_限定_,即更改前面的“*”,因此完整模式是“*(N)”。限定符改变模式的行为方式,在这种情况下,如果没有匹配,限定符会使模式消失。 (2认同)

Goo*_*Pen 5

在交互式 zsh 中输入:

setopt no_nomatch
rm * > /dev/null 2>&1
setopt nomatch  # `nomatch` is default, see `man zshoptions`
Run Code Online (Sandbox Code Playgroud)

对我来说,nullglobcshnullglob工作