如何根据`find`输出删除目录?

Arn*_*aud 200 subversion find rm

我发出以下命令来查找 .svn 目录:

find . -name ".svn"
Run Code Online (Sandbox Code Playgroud)

这给了我以下结果:

./toto/.svn
./toto/titi/.svn
./toto/tata/.svn
Run Code Online (Sandbox Code Playgroud)

我如何处理所有这些行rm -fr以删除目录及其内容?

Dra*_*oan 255

Find 可以使用-exec它找到的每个匹配项的选项执行参数。这是推荐的机制,因为您可以正确处理包含空格/换行符和其他字符的路径。您必须先删除目录的内容,然后才能删除目录本身,因此请使用-rrm命令来实现此目的。

对于您的示例,您可以发出:

find . -name ".svn" -exec rm -r "{}" \;
Run Code Online (Sandbox Code Playgroud)

您还可以通过添加检查来告诉 find 仅查找名为 .svn 的目录-type d

find . -name ".svn" -type d -exec rm -r "{}" \;
Run Code Online (Sandbox Code Playgroud)

警告rm -r谨慎使用它会删除文件夹及其所有内容。

如果您只想删除空目录以及仅包含空目录的目录, find 可以使用-deleteand自行完成-empty

find . -name ".svn" -type d -empty -delete
Run Code Online (Sandbox Code Playgroud)

  • 我已经看到建议总是在 find 命令中运行 `-type` *after* `-name`,因为调用 `stat` 来获取类型的成本很高。我只是在相当大的一堆文件上自己尝试过,这似乎是真的:运行 `find 。-name 'foo' -type d` 耗时 19 秒,而 `find . -type d -name 'foo'` 耗时 32 秒。所以先运行 `-type` 的时间增加了大约 50%。 (35认同)
  • 我多年来一直在使用这个命令,但现在在 Mac 上我收到错误消息,说这些目录不存在。即使它确实删除了它们。我以前从未见过消息。 (11认同)
  • @chovy @Clément 我认为 `-depth` 参数解决了这个问题:`find 。-depth -name ".svn" -type d -exec rm -r "{}" \;` (7认同)
  • @chovy @clément 那是因为`find` 希望在该文件夹中查看其他匹配项,同时删除该文件夹。〜我还不知道如何解决这个问题。〜肮脏的修复:`find 。-name "要删除的文件夹" -print0 | xargs -r0 -- rm -r` (3认同)
  • 与@chovy 相同。有没有办法摆脱这些消息? (2认同)

jll*_*gre 89

这是一种比公认的答案方式更快的便携式方法。

使用 a+而不是分号作为find命令终止符可以优化 CPU 使用率。如果您有很多.svn子目录,这可能很重要:

find . -name .svn -type d -exec rm -rf {} +
Run Code Online (Sandbox Code Playgroud)

还需要注意的是你永远不1个必要在这里引用大括号内。

1除非你使用fishshell(这可能在我写这篇回复后已经解决了)。

  • + 和分号有什么区别?为什么我们不使用花括号? (6认同)
  • @ShichengGuo 使用分号,找到的每个目录将有一个 rm 命令,使用 + 单个 rm 命令将处理找到的所有目录(或至少其中非常多的目录。)我不明白你的第二个问题,卷曲这里使用大括号。 (3认同)
  • @gaoithe 我确实回滚了您编辑的内容,它用不正确的语句替换了正确的语句。使用`+` **确实**降低CPU使用率,使用`;`**不会**导致命令过长错误。 (2认同)

小智 31

假设您使用的是gnu find,您可以使用以下-delete选项:

find . -name test -delete
Run Code Online (Sandbox Code Playgroud)

这更容易记住。

  • 这不适用于非空目录。 (124认同)
  • 选项顺序非常重要,find 会按顺序执行它们,所以 -delete 必须是最后一个 (3认同)
  • 也适用于 Mac OS X (2认同)

小智 15

在我的电脑上使用时:

find . \( -name dirname -type d \) -exec rm -r '{}' ';'
Run Code Online (Sandbox Code Playgroud)

目录被删除,但我收到错误:

find: ‘./dirname’: No such file or directory
Run Code Online (Sandbox Code Playgroud)

对于每个目录。

我的目录不是空的,所以 -delete 选项对我不起作用。我在这里找到了这种行为的原因:

  1. find 获取(不一定) ./ 目录中的第一个条目。这将是例如 dir.1/
  2. 它将它与模式 'dir.?' 进行比较。它匹配吗?是的。
  3. find 执行“rm -r dir.1”。
  4. find 尝试输入 dir.1/ 以查找目录中的模式。它对 exec 命令一无所知。
  5. 它不再找到 dir.1/ 。返回 ENOENT(查看 strace 输出)

我用它来解决:

rm -r `find . -name dirname -type d`
Run Code Online (Sandbox Code Playgroud)

请记住, find 仍会尝试递归到名为 dirname 的目录,这并不是必需的,并且会花费一些额外的时间。根据您的目录结构,您可以使用--depthfind 选项解决此问题。此外,如果您有一个目录结构,如 dirname/foo/dirname,您将从 rm 收到“没有这样的文件或目录”错误。要抑制错误,您可以将 stderr 重定向到 /dev/null 或将-f(force) 标志与 rm 一起使用。

  • 坏主意:带空格的文件名会导致各种可怕的问题 (3认同)
  • 对于未来的读者:`find . -name "to-delete" -print0 | xargs -r0 -- rm -r` 是一个防故障版本,不会在空间上崩溃 (3认同)
  • 请参阅 http://unix.stackexchange.com/a/115869/8257 您需要添加 `-prune`。 (3认同)
  • 添加 `-prune` 以避免“没有这样的文件或目录”错误。 (2认同)

Cha*_*eng 14

更快的方法是:

find . -name ".svn" -type d -prune -exec rm -rf '{}' '+'
Run Code Online (Sandbox Code Playgroud)

如果您在另一个“.svn”中有“.svn”。

  • 使用 `-prune` 是最准确的方法。谢谢! (2认同)

rus*_*ush 7

Bash特定的解决方案:

shopt -s globstar
rm -r **/.svn
shopt -u globstar #optional. this will disable globstar expansion
Run Code Online (Sandbox Code Playgroud)

  • 请注意,对于匹配许多文件的 glob 的命令行扩展,您可以使用此机制匹配的文件数量有限制。超过这个限制会导致`bash: /bin/rm: Argument list too long` (4认同)

Mag*_*nus 6

我发现该-delete操作在-path测试中效果很好。例如,以下应该适用于原始海报问题:

find . -path '*/.svn*' -delete
Run Code Online (Sandbox Code Playgroud)

请注意,除了删除“.svn”目录(及其内容)之外,这还将删除名称以“.svn”开头的任何文件或目录。例如,如果您使用-path '*/.git*'它,除了“.git/”之外,它还将删除“.gitignore”和“.gitattribute”。为避免这种情况,只需删除具有该确切名称的目录,请使用:

find . -path '*/.svn/*' -or -name '.svn' -delete
Run Code Online (Sandbox Code Playgroud)

注意 .svn 后面的斜杠。这将首先查找并删除“.svn”下的所有文件,然后删除 .svn 目录本身。