![在 zsh 中使用带通配符的 `rm` 来表示多个目录时,如何忽略空目录?](https://linux22.com/image/102874/%E5%9C%A8%20zsh%20%E4%B8%AD%E4%BD%BF%E7%94%A8%E5%B8%A6%E9%80%9A%E9%85%8D%E7%AC%A6%E7%9A%84%20%60rm%60%20%E6%9D%A5%E8%A1%A8%E7%A4%BA%E5%A4%9A%E4%B8%AA%E7%9B%AE%E5%BD%95%E6%97%B6%EF%BC%8C%E5%A6%82%E4%BD%95%E5%BF%BD%E7%95%A5%E7%A9%BA%E7%9B%AE%E5%BD%95%EF%BC%9F.png)
当我尝试删除 中两个或多个子目录中的所有文件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
与 不同bash
,zsh
默认情况下,如果文件名生成模式没有匹配项,则会报告错误。此行为可以全局更改或基于每个模式进行更改。
要防止全局不匹配模式出现错误消息,您可以设置以下选项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.
您的空目录将不会生成任何匹配项,从而产生错误。正如答案所示,您可以:
- 将参数括在引号中(例如
rm -r "dir1/*" "dir2/*"
)或 unsetopt nomatch
在您的文件中设置.zshrc
或- 您可以使用环境变量进行命令
noglob
(例如noglob rm -r dir1/* dir2/*
)