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
?