为什么 find with -delete 删除了我的 /save/ 目录中的文件,而 find without delete 无法找到它们?

Oth*_*eus 21 find

我想删除当前目录树中的所有文件,除了save. 我运行了这个命令:

 find . \( -name save -prune \) -o -type f -ls | grep /save/
Run Code Online (Sandbox Code Playgroud)

它没有找到。但是当我运行这个命令时:

 find . \( -name save -prune \) -o -type f -delete
Run Code Online (Sandbox Code Playgroud)

/save/ 中的所有文件都消失了。我错过了什么?

Sté*_*las 27

-delete意味着-depth这不适用于-prune(-depth从叶子开始)。在 GNU 版本的手册中对此有一个警告(-delete现在 GNUfind和其他一些实现也支持 FreeBSD 扩展)。

info -- find -delete
Run Code Online (Sandbox Code Playgroud)

在命令行上使用“-delete”操作会自动打开“-depth”选项(*note find Expressions::)。如果您之前只是使用“-print”进行测试,这可能会令人惊讶,因此通常最好记住明确使用“-depth”。

info -- find -prune
Run Code Online (Sandbox Code Playgroud)

因为“-delete”意味着“-depth”,将“-prune”与“-delete”结合使用很可能会导致删除的文件比预期的多。

在这里,您可以选择使用rm

find . -name save -prune -o -type f -exec rm -f {} +
Run Code Online (Sandbox Code Playgroud)

(如果那里有其他人可写的目录,则可能不安全,因为在运行该命令时,可以通过用符号链接替换目录来删除当前目录树之外的文件)。

更安全的选择:

find . -name save -prune -o -type f -execdir rm -f -- {} \;
Run Code Online (Sandbox Code Playgroud)

那没有上面提到的问题,但意味着rm每个文件运行一个。在--对FreeBSD的实现,而不是GNU一个前缀的文件名与是必要的./

或者,正如科斯塔斯所建议的那样:

LC_ALL=C find . ! -name save ! -path '*/save/*' -type f -delete
Run Code Online (Sandbox Code Playgroud)

(但这仍然不必要地下降到save目录中)

LC_ALL=C是有这么*任何字节序列(即使是那些没有在当前区域形成有效的字符)相匹配。请注意,它会影响错误消息的语言(英语而不是用户的语言)。