在 zsh 中使用带通配符的 `rm` 来表示多个目录时,如何忽略空目录?

在 zsh 中使用带通配符的 `rm` 来表示多个目录时,如何忽略空目录?

当我尝试删除 中两个或多个子目录中的所有文件zsh,并且目录已为空时,将忽略以下目录,并保留文件。

例子:

$ mkdir dir1
$ mkdir dir2
$ touch dir2/blah

# avoid the zsh safety prompt; this may not be necessary for this
# example, just for ease of use here
$ setopt rm_star_silent
$ rm -r dir1/* dir2/*
zsh: no matches found: dir1/*
$ ls dir2
blah

在 bash 中,已经为空的目录不会停止rm继续进行dir2,并且dir2/blah会被删除。

这个zsh功能是什么,有没有办法让其rm表现得像 in bash

答案1

与 不同bashzsh默认情况下,如果文件名生成模式没有匹配项,则会报告错误。此行为可以全局更改或基于每个模式进行更改。

要防止全局不匹配模式出现错误消息,您可以设置以下选项NULL_GLOB之一CSH_NULL_GLOB

  • setopt nullglob
    

    如果模式没有匹配项,它将从参数列表中删除。不会打印任何错误消息。在你的例子中

    rm dir1/* dir2/*
    

    将只是扩展到

    rm dir2/blah
    
  • setopt cshnullglob
    

    还删除不匹配的模式并且不打印错误消息,除非没有任何模式匹配。

为了防止单个模式出现错误消息,您可以使用 glob 限定符N,其行为就像NULL_GLOB为此模式激活了该选项:

rm dir1/*(N) dir2/*(N)

这也将扩展到

rm dir2/blah

答案2

最好的方法是使其成为一个与两个目录中的文件相匹配的单个 glob。

rm (dir1|dir2)/*

这样,如果没有找到文件,该命令仍然不会运行。

但请注意dir1/dir2不能包含/.

在这些情况下,您可以这样做:

files=(foo/bar/*(N) bar/baz/*(N))
if ((#files)); then
  rm $files
else
  echo >&2 No matching file
fi

或者用于cshnullglob获取 csh 或 Bourne sh 之前的行为。这仍然比恢复到虚假(IMO)行为bash(其中不匹配的全局对象被传递给命令)更好,您可以这样做:

set +o nomatch

答案3

可以在这里找到一个很好的解释:

https://superuser.com/questions/584249/using-wildcards-in-commands-with-zsh

要点是:

By default, ZSH will generate the filenames and throw an error before executing the command if it founds no matches.

您的空目录将不会生成任何匹配项,从而产生错误。正如答案所示,您可以:

  1. 将参数括在引号中(例如rm -r "dir1/*" "dir2/*")或
  2. unsetopt nomatch在您的文件中设置.zshrc
  3. 您可以使用环境变量进行命令noglob(例如noglob rm -r dir1/* dir2/*

相关内容