删除给定名称的目录的所有内容,保持目录完整

删除给定名称的目录的所有内容,保持目录完整

考虑以下问题的答案这个问题关于按名称删除文件夹和这个问题关于在路径树中的第一个正数处停止搜索,如何删除目录的所有内容,包括子目录和文件,同时保持目录完整并在路径树中的第一个匹配处停止?

换句话说我可能会:

./path/to/foo/again/foo

./path/to/foo 文件夹包含一个 bar.txt 文件,我希望获得:

./path/to/foo

不包含文件或目录。

答案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

相关内容