TL; DR:最好的方法是使用-exec rm代替-delete。
find a \( -name b -prune \) -o -type f -exec rm {} +
说明:
为什么找抱怨当您尝试使用-delete带-prune?
答案很简单:因为-delete暗示-depth和-depth使-prune无效。
在得出详细答案之前,请先观察带有和不带有find的行为-depth:
$ find foo/
foo/
foo/f1
foo/bar
foo/bar/b2
foo/bar/b1
foo/f2
无法保证单个目录中的订单。但是可以保证目录在目录内容之前被处理。注意foo/之前foo/*和foo/bar之前foo/bar/*。
可以用反转-depth。
$ find foo/ -depth
foo/f2
foo/bar/b2
foo/bar/b1
foo/bar
foo/f1
foo/
请注意,现在所有内容都foo/*出现在之前foo/。与相同foo/bar。
更长的答案:
-prune防止查找下降到目录。换句话说,-prune跳过目录的内容。就您而言,-name b -prune阻止find进入名称为的任何目录b。
-depth可以在目录本身之前处理目录的内容。这意味着到查找开始处理目录条目时,b其内容已被处理。因此-prune实际上是无效的-depth。
-delete意味着-depth可以先删除文件,然后删除空目录。-delete拒绝删除非空目录。我猜可能会添加一个选项来强制-delete删除非空目录和/或防止-delete隐含目录-depth。不过那是另一回事了。
还有另一种方法可以实现您想要的:
find a -not -path "*/b*" -type f -delete
这可能不容易记住。
该命令仍然会进入目录b并处理其中的每个文件,仅用于-not拒绝它们。如果目录b很大,这可能是性能问题。
-path工作原理与有所不同-name。-name仅匹配(文件或目录的)名称,而-path匹配整个路径。例如观察路径/home/lesmana/foo/bar。-name -bar将匹配,因为名称是bar。-path "*/foo*"将匹配,因为字符串/foo在路径中。-path使用前,您应该了解一些复杂的知识。阅读的手册页以find获取更多详细信息。
请注意,这并非100%可靠。有可能出现“误报”。该命令的上方编写方式将跳过具有其父目录名称(以b(正)开头)的任何文件。但是,b无论树中的位置如何,它都将跳过名称以其开头的任何文件(误报)。可以通过编写比更好的表达式来解决此问题"*/b*"。这留给读者作为练习。
我假设您使用a和b作为占位符,真实姓名更像allosaurus和brachiosaurus。如果您brachiosaurus替换掉,b那么误报的数量将大大减少。
至少不会误报,因此不会那么可悲。此外,您可以通过先不带命令运行命令来检查误报-delete(但请记住放置暗示的内容-depth)并检查输出。
find a -not -path "*/b*" -type f -depth
a除了,您如何包括所有内容a/b?