答案1
请注意,第二个链接(“关于在路径树中的第一个正数处停止搜索”)实际上并不相关,因为忽略它的解决方案可能会先清空./path/to/foo/again/foo
,然后清空./path/to/foo
;或者它可能./path/to/foo
先清空,然后根本无法到达./path/to/foo/again/foo
(因为这条路径现在不存在)。无论如何,目标都会实现。
(some) 下的任何内容都foo
与 匹配-path '*/foo/*'
,但./path/to/foo
本身不匹配。find
不会在其创建和检查的路径中添加尾部斜杠。例外情况是,类似于find /path/to/foo/ …
where 的内容/path/to/foo/
将以尾部斜杠处理,并且它将要匹配-path '*/foo/*'
。你可以考虑-path '*/foo/?*'
,但如果你从/path/to/foo//
(这是一个有效的路径名) 那么它将匹配。
所以也许-path
和 -name
?
find . -path '*/foo/*' ! -name foo
它会给你一个要删除的路径名列表吗?注意./path/to/foo/again/foo
不会。列表将包含./path/to/foo/again
,因此如果你again
正确删除,则./path/to/foo/again/foo
无论如何都会被删除。还不错,直到你意识到列表中没有允许你删除的条目./path/to/foo/foo/foo
(如果存在这样的路径)。
的另一个问题-path '*/foo/*'
是,当您以 的形式提供 的起点时/a/foo/starting/point
。在这种情况下, 考虑的每条路径find
都将匹配。实际上,您可能会无意中删除整个point
,而您的意图是清空/a/foo/starting/point/whatever/foo/
。
如果你能cd
到达起点那么这应该是安全的:
cd /whatever/the/starting/point
# check if cd succeeded (the check can be automated with cd … && find … )
find . -path '*/foo/?*' -delete
(?
很可能不需要,因为规格明确指出相对于我们作为起始路径提供的路径名部分中不应该有尾随斜杠;但我不知道find
在野外的所有实现是否都严格遵守;所以?
只是以防万一)。
即使foo
出现在 的路径中starting/point
,也没有关系。在测试find
中-path
,工具构建的路径名,而不是实际的绝对路径名。当 find 从 开始时,.
它构建的所有路径名都将以 开头,.
并将-path
它们作为字符串进行测试。
笔记-delete
不可移植。便携式解决方案可能是以下之一:
find . -depth -path '*/foo/?*' -exec rm -r {} +
find . -path '*/foo/?*' -exec rm -r {} \;
第一个的工作原理如下-delete
(这意味着-depth
):它仅在处理完所有内容后才处理目录。rm
将按正确的顺序逐个获取路径名,并且实际上不需要递归工作,因为它尝试删除的任何目录都应该已经为空(仍然需要,以便它可以删除目录)。由于,-r
将向单个目录提供多个路径名,但可能还会有多个,因为rm
+
rm
你不能rm
用任意多的参数来运行.find -exec … +
知道这一点,并且可以执行尽可能多的命令(rm
在我们的例子中是进程),因为它需要处理任意数量的条目而不会达到限制(为了比较:xargs
也知道这一点)。
在许多情况下,最优的可移植解决方案是运行一个或几个rm -r
进程来删除非目录和直接位于 之下的目录./path/to/foo/
,因此find
甚至不需要更深入。这是第二条命令所做的。请注意,有;
(从 shell 中转义)而不是+
。我们不希望+
因为可能发生的情况find
决定 的内容./path/to/foo/
不足以rm
使用许多参数运行,它会更深入地添加更多参数,找到 的内容./path/to/foo/again/foo/
,然后才启动rm
。因此rm -r
获取./path/to/foo/again
和(可能还包括其他)./path/to/foo/again/foo/whatever
,它会删除前者(递归),然后它会抱怨后者不存在。因此,当没有 时-depth
,最好rm
每个路径名运行一个,所以-exec … \;
。
但即便如此,不再存在的文件也可能会触发警告;不是来自rm
而是来自find
。这是因为find
在处理目录之前会了解目录的内容。即使它要先处理目录(即即使没有-depth
),它也会这样做。rm
删除后./path/to/foo/again
find
仍会尝试处理./path/to/foo/again/whatever
。任何带有(显式或隐式)的解决方案-depth
都不会出现此问题。
使用第一个可移植形式,即带有 的形式-depth
;或者更好的是带有 的形式-delete
,如果只有您的find
支持-delete
。
附注:如果你想清空具体的然后cd
进入目录并:
# check if in the right directory
find . ! -name . -delete
使用常见的实现find
你甚至不需要! -name .
因为他们不会删除.
,这是设计使然。该命令简化为:
find . -delete