有效删除包含数千个文件的大目录

Tob*_*oby 233 linux command-line rm files

我们有一个文件夹变得笨重的问题,其中包含数十万个小文件。

执行rm -rf返回错误的文件太多了,而我们需要做的是:

find /path/to/folder -name "filenamestart*" -type f -exec rm -f {} \;

这有效,但速度非常慢,并且经常因内存不足而失败。

有一个更好的方法吗?理想情况下,我想删除整个目录而不关心其中的内容。

小智 313

使用 rsync 非常快速和简单。

mkdir empty_dir
rsync -a --delete empty_dir/    yourdirectory/
Run Code Online (Sandbox Code Playgroud)

@sarath 的回答提到了另一个快速选择:Perl!?它的基准测试比rsync -a --delete.

cd yourdirectory
perl -e 'for(<*>){((stat)[9]<(unlink))}'
Run Code Online (Sandbox Code Playgroud)

或者,没有stat(是否需要它是有争议的;有人说使用它可能更快,而其他人说没有它更快):

cd yourdirectory
perl -e 'for(<*>){unlink}'
Run Code Online (Sandbox Code Playgroud)

资料来源:

  1. /sf/ask/125675931/
  2. http://www.slashroot.in/which-is-the-fastest-method-to-delete-files-in-linux
  3. https://www.quora.com/Linux-why-stat+unlink-can-be-faster-than-a-single-unlink/answer/Kent-Fredric?srid=O9EW&share=1

  • `rsync` 可以比普通的 `rm` 更快,因为它保证删除的顺序正确,因此需要更少的 btress 重新计算。请参阅此答案 http://serverfault.com/a/328305/105902 (23认同)
  • 任何人都可以修改 perl 表达式以递归删除 **directory_to_be_deleted** 中的所有目录和文件吗? (13认同)
  • 注意:在 rsync 中添加 `-P` 选项以获得更多显示,另外,注意语法,尾部斜杠**是**强制性的。最后,您可以使用 `-n` 选项第一次启动 rsync 命令以启动 _dry run_。 (12认同)
  • Ubuntu 20.04 的 perl 命令什么也不做。有人有递归 perl 变体吗?有没有办法让rsync有进度条?我尝试了 -P 和 --info=progress2 但没有进度条。 (8认同)
  • 谢谢,很有用。我一直在使用 rsync,我不知道你可以用它来像这样删除。比 rm -rf 快得多 (4认同)
  • 在 ubuntu 18.04 上,perl 似乎只是运行而不执行任何操作 (4认同)
  • **** 极度谨慎 **** 是 Gobinath(上面的评论)在上面的 github.com 地址上生成的脚本。从我的实验来看,它可能会导致数据意外丢失……特别是我相信它似乎会导致符号链接被探索并删除它们的内容。我建议大家在认真使用之前先进行长时间的试验! (3认同)
  • `-a` 等于 `-rlptgoD`,但删除时只需要 `-rd` (2认同)
  • 警告:附加的 Perl 代码可能不是最理想的,因为使用的某些操作没有任何合理的理由。引用的文章也不知道为什么,并且“stat”调用在测试中明显减慢了速度:https://www.quora.com/Linux-why-stat+unlink-can-be-faster- than-a-single-unlink/answer/Kent-Fredric?srid=O9EW&amp;share=1 (2认同)
  • 该 perl 命令不起作用 (2认同)

Tob*_*oby 47

在有人Twitter的使用建议-delete,而不是-exec rm -f{} \;

这提高了命令的效率,但它仍然使用递归来遍历所有内容。

  • 这是非标准的。GNU `find` 有 `-delete`,可能还有其他 `find`。 (14认同)
  • 出于安全和效率的原因,`-delete` 在可用时应始终优先于 `-exec rm`。 (14认同)
  • GNU 是*事实上的* 标准。 (8认同)
  • 只是一个警告 - 在 gnu find 中添加 `-delete` 会隐式启用 `-深度`,这会让您回到扫描期间内存不足的问题。 (3认同)

MZA*_*web 28

一个巧妙的技巧:

rsync -a --delete empty/ your_folder/
Run Code Online (Sandbox Code Playgroud)

这是超级 CPU 密集型,但真的非常快。见https://web.archive.org/web/20130929001850/http://linuxnote.net/jianingy/en/linux/a-fast-way-to-remove-huge-number-of-files.html

  • @Marki555:在问题的编辑中,`rsync -a --delete` 为 60 秒,`lsdent` 为 43 秒。比率 10x 是针对 `time ls -1 | wc -l` vs `time ./dentls bigfolder &gt;out.txt`(这是一个部分公平的比较,因为 `&gt; file` vs `wc -l`)。 (2认同)

dig*_*ity 19

怎么样: find /path/to/folder -name "filenamestart*" -type f -print0 | xargs -0rn 20 rm -f

您可以通过更改 parameter 的参数来限制一次删除的文件数-n。还包括带空格的文件名。

  • 您可能不需要 `-n 20` 位,因为无论如何 xargs 应该将自身限制为可接受的参数列表大小。 (2认同)

Izk*_*ata 14

扩展其中一条评论,我认为您没有在做您认为正在做的事情。

首先,我创建了大量文件,以模拟您的情况:

$ mkdir foo
$ cd foo/
$ for X in $(seq 1 1000);do touch {1..1000}_$X; done
Run Code Online (Sandbox Code Playgroud)

然后我尝试了我期望失败的方法,以及您在问题中所做的事情:

$ rm -r foo/*
bash: /bin/rm: Argument list too long
Run Code Online (Sandbox Code Playgroud)

但这确实有效:

$ rm -r foo/
$ ls foo
ls: cannot access foo: No such file or directory
Run Code Online (Sandbox Code Playgroud)

  • 这是唯一有效的解决方案:多次运行 `rm -Rf bigdirectory`。我有一个包含数以百万计的子目录和文件的目录。我什至无法在该目录中运行 `ls` 或 `find` 或 `rsync`,因为它的内存不足。命令 `rm -Rf` 多次退出(内存不足),只删除了数十亿文件中的一部分。但经过多次重试后,它终于完成了这项工作。如果内存不足是问题,这似乎是唯一的解决方案。 (7认同)

小智 10

我有机会测试-delete相比-exec rm \{\} \;,对我来说-delete就是这个问题的答案。

使用-delete删除文件夹中 400,000 个文件的文件至少比rm.

“如何在 linux 中删除大量文件”一文表明它大约快了三倍,但在我的测试中,差异要大得多。

  • 使用 `find -exec` 为每个文件分别执行 `rm` 命令,这就是它如此缓慢的原因。 (4认同)

Jos*_*ter 10

使用rm -rf directory代替rm -rf *

我们最初rm -rf *是在目录中清除内容,并认为这是尽可能快的。但是后来我们的一位高级工程师建议我们避免使用星号 ( *),而是传入父目录,例如rm -rf directory.

在关于这不会产生什么影响的激烈辩论之后,我们决定对其进行基准测试,以及使用find. 结果如下:

time rm -rf *                   2m17.32s
time rm -rf directory           0m15.60s
time find directory -delete     0m16.97s
Run Code Online (Sandbox Code Playgroud)

rm -rf directory大约比rm -rf *!快 9 倍!

不用说,我们给那个工程师买了啤酒!

所以现在我们使用rm -rf directory; mkdir directory删除目录并重新创建它。

  • 问题在于 * 进行了 shell 扩展,这意味着:(a) 它读取整个目录,然后 (b) 对所有文件名进行排序,甚至在调用 find 之前也是如此。使用 ls -1 -U 按串行顺序读取目录。您可以 head -n 10000 并获取要发送到 xargs rm 的列表。而且由于这些名称在目录的第一部分中都是连续的,因此它们也会被有效地删除。只要将其放入一个循环中,直到没有文件剩余,它就可以很好地工作。 (2认同)

小智 6

关于-delete上面的选项:我正在使用它删除我创建的临时文件夹中的大量(1M+ est)文件,但无意中忘记了每晚清理。我不小心填满了我的磁盘/分区,除了find .命令之外没有其他任何东西可以删除它们。它很慢,起初我使用的是:

find . -ls -exec rm {} \;
Run Code Online (Sandbox Code Playgroud)

但这需要花费大量时间。它在大约 15 分钟后开始删除一些文件,但我的猜测是它在最终启动后每秒删除不到 10 个左右。所以,我尝试了:

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

相反,我现在让它运行。它似乎运行得更快,尽管它对 CPU 的负担非常大,而另一个命令则没有。它已经运行了大约一个小时,我想我的驱动器上的空间正在恢复,并且分区逐渐“缩小”,但仍然需要很长时间。我严重怀疑它的运行速度比另一个快 1,000 倍。和所有事情一样,我只是想指出空间与时间的权衡。如果您有足够的 CPU 带宽(我们有),则运行后者。它让我的 CPU 正在运行(uptime报告):

10:59:17 up 539 days, 21:21,  3 users,  load average: 22.98, 24.10, 22.87
Run Code Online (Sandbox Code Playgroud)

我已经看到平均负载超过 30.00,这对于繁忙的系统来说并不好,但对于我们通常负载较轻的系统来说,几个小时就可以了。我已经检查了系统上的大多数其他内容,它们仍然有响应,所以我们现在还可以。

  • 如果您要使用“exec”,您几乎肯定不想使用“-ls”并执行“find”。-type f -exec rm '{}' +` + 速度更快,因为它会向 rm 提供一次可以处理的尽可能多的参数。 (3认同)
  • 平均负载并不总是 CPU,它只是衡量一段时间内阻塞进程的数量。进程可能会阻塞磁盘 I/O,这很可能就是这里发生的情况。 (3认同)

小智 5

有几种方法可用于在 linux 中删除大量文件。您可以将 find 与 delete 选项一起使用,这比 exec 选项更快。然后你可以使用 perl unlink,然后甚至是 rsync。 linux下如何删除大量文件


Ser*_*erg 5

考虑使用 Btrfs 卷并简单地删除具有大量文件的目录的整个卷。

或者,您可以创建一个 FS 映像文件,然后卸载并删除其文件,以非常快地立即删除所有内容。


小智 -1

ls -1 | xargs rm -rf 
Run Code Online (Sandbox Code Playgroud)

应该在主文件夹内工作

  • @Toby:尝试“ls -f”,它会禁用排序。排序需要将整个目录加载到内存中进行排序。未排序的“ls”应该能够流式传输其输出。 (5认同)
  • 不适用于包含换行符的文件名。 (2认同)