我想删除在多个子目录中有大量文件的目录中的旧文件。
我正在尝试使用以下方法 - 经过一些谷歌搜索后,它似乎是推荐且有效的方法:
find . -mindepth 2 -mtime +5 -print -delete
Run Code Online (Sandbox Code Playgroud)
我的期望是,这应该打印一个满足条件的文件(5 天前修改并满足 mindepth 条件),然后将其删除,然后继续下一个文件。
但是,当这个命令运行时,我可以看到 find 的内存使用量在增加,但没有打印任何内容(因此我认为还没有删除任何内容)。这似乎意味着find首先收集满足条件的所有文件,在遍历整个文件系统树后,它会打印然后删除文件。
有没有办法让它在对文件运行测试后立即删除它?这将有助于逐步清理 - 我可以选择终止命令,然后稍后重新运行它(这将有效地恢复文件删除)。这目前似乎没有发生,因为 find 在遍历巨大的文件系统树之前还没有开始删除任何内容。有没有办法解决?
编辑 - 包括有关我的用例的请求数据:
我必须清理的目录最大深度约为 4;常规文件仅存在于文件系统的叶子上。大约有大约 6 亿个常规文件,其中叶目录最多包含 5 个文件。较低级别的目录扇出大约为 3。较高级别的扇出很大。单个 7.2TB LVM 磁盘(带有 4 个约 2 TB 的物理硬盘)上占用的总空间为 6.5TB
Vol*_*gel 13
这是一个非常有趣的问题......或者,老实说,恶意:
命令
find . -mindepth 2 -mtime +5 -print -delete
与通常的试用版本非常不同,省略了危险的部分,-delete:
find . -mindepth 2 -mtime +5 -print
棘手的部分是 action-delete 隐含了 option -depth。包括删除的命令真的是
find . -depth -mindepth 2 -mtime +5 -print -delete
并且应该用
find . -depth -mindepth 2 -mtime +5 -print
这与你看到的症状密切相关;该选项-depth是将文件系统树的树遍历算法从preorder depth-first search更改为inorder depth-first search。
以前,到达的每个文件或目录都会立即使用,然后被遗忘。Find 正在使用树本身来找到它的方式。find现在需要收集所有可能包含仍待找到的文件或目录的目录,然后首先删除最深目录中的文件. 为此,它需要自己完成规划和记住遍历步骤的工作,而且——这就是重点——以不同于文件系统树自然支持的顺序。因此,确实,它需要在输出工作的第一步之前收集许多文件的数据。
Find 必须跟踪一些目录以供以后访问,这对于少数目录来说不是问题。
但也许有很多目录,不同程度的很多。
此外,在这种情况下,find 之外的性能问题会变得很明显;所以有可能它甚至find不是很慢,而是其他的东西。
其性能和内存影响取决于您的目录结构等。
相关部分来自man find:
请参阅“警告”:
ACTIONS
-delete
Delete files; true if removal succeeded. If the removal failed,
an error message is issued. If -delete fails, find's exit status
will be nonzero (when it eventually exits). Use of -delete auto?
matically turns on the -depth option.
Warnings: Don't forget that the find command line is evaluated as
an expression, so putting -delete first will make find try to
delete everything below the starting points you specified. When
testing a find command line that you later intend to use with
-delete, you should explicitly specify -depth in order to avoid
later surprises. Because -delete implies -depth, you cannot use?
fully use -prune and -delete together.
[ ... ]
Run Code Online (Sandbox Code Playgroud)
而且,从更进一步的部分:
OPTIONS
[ ... ]
-depth Process each directory's contents before the directory itself.
The -delete action also implies -depth.
Run Code Online (Sandbox Code Playgroud)
您真的不需要在删除文件的同一运行中删除目录,对吗?如果我们不删除目录,我们不需要整个-depth事情,我们可以找到一个文件并将其删除,然后按照您的建议继续下一步。
这次我们可以使用简单的打印变体来测试find,带有隐式-print.
我们只想找到纯文件,没有符号链接、目录、特殊文件等:
find . -mindepth 2 -mtime +5 -type f
我们习惯于xargs在每个rm启动的进程中删除多个文件,通过使用空字节作为分隔符来处理奇数文件名:
测试此命令 - 请注意echo前面的rm,以便打印稍后将运行的内容:
find . -mindepth 2 -mtime +5 -type f -print0 | xargs -0 echo rm
行将很长且难以阅读;对于初始测试,它可以通过添加-n 3作为第一个参数来帮助获得每行只有三个文件的可读输出xargs
如果一切正常,请删除echo前面的rm并再次运行。
那应该快很多;
如果我们谈论的是数百万个文件——你写的总共有 6 亿个文件——还有更多需要考虑的事情:
大多数程序,包括find,使用库调用读取目录readdir (3)。这通常使用 32 KB 的缓冲区来读取目录;当包含大量可能很长的文件名的目录很大时,这就会成为一个问题。
解决它的方法是直接使用系统调用读取目录条目
getdents (2),并以更合适的方式处理缓冲。
详情请看你可以列出一个包含800万个文件的目录!但不是 ls..
(如果您可以在您的问题中添加有关每个目录的典型文件数、每个目录的目录、路径的最大深度;另外,使用哪个文件系统的详细信息,那将会很有趣。)
(如果它仍然很慢,您应该检查文件系统性能问题。)