高效合并 500 万个文件

高效合并 500 万个文件

由于一些糟糕的规划,我的目录包含超过 500 万个文件,总计大约 20GB。每个文件的顶部包含 32 行垃圾,后面跟着未知行数的重要数据。

我想将所有重要数据合并到一个文件中。

我正在这样做:

for i in $(find); do tail -n +32 $i >> ../all.txt; done

all.txt 每秒仅增长约 0.5MB。有没有更快的方法来完成这个任务?另外,删除文件会很方便,因为在完成工作之前我可能会用完磁盘空间:X

任何建议表示赞赏。

答案1

如果需要随时删除文件,那么您编写的内容已经是一种快速的方法。一种优化是,find您可以使用 来列出文件内容,而不是使用*来列出文件,因为它们在目录列表中列出,而不会产生额外的处理时间find。也就是说,你会写:

for i in *; do tail -n +3 $i >> ../x; rm $i; done

但是,如果您可以在完成合并之前删除它们,并且如果您还希望保留哪些内容来自哪个文件,则有一种方法可以一次解析它们以跟踪多个(与您的 shell 一样多)允许)。执行此操作的命令是:

find . -exec tail -n +3 {} >> ../x +

最后+会告诉find一次传递多个文件名,而不是一次传递一个。这将导致性能的巨大提高(由于调用的实例数量少得多tail),但您的输出文件仍然会有类似的内容

==> ./filename <==

每次一个文件结束而下一个文件开始时打印。此外,这些文件不会随您删除。

如果您想以牺牲一点速度为代价删除上面的行,您可以通过以下方式运行它

find . -exec awk 'FNR>32' {} + 

(感谢 dave_thompson 的建议作为评论)。

最后,如果您更喜欢列出哪些信息来自哪个文件的输出,并且仍然想随时删除它们,您可以使用 iruvar 的答案来执行此操作,将两个\;' ' 替换为+' ' ' (我最初的答案仅描述了要做什么; iruvar 给出了实际的命令)。

答案2

您的流程可能受 IO 限制,因此优化循环最多只能产生边际改进。如果您可以对文件进行深度优先操作,则可以将tailrm调用滚动到 中find,并在进行时删除

使用 GNU find

find . -type f -exec tail -n +32 {} \; -delete >../all.txt

理想情况下,我们希望能够通过替换来一次find传递多个文件,但我似乎无法让它与tail\;+-delete

缺乏find选择-delete

find . -type f -exec tail -n +32 {} \; -exec rm {} \; >../all.txt

或者在 GNU 系统上,允许传递-qto 来在接收多个文件tail时抑制文件头的打印:tail

find . -type f -exec tail -q -n +32 {} + -exec rm {} + >../all.txt    

注意 - 对于-exec rm,适用于的深度优先搜索-delete不再适用 这最后一个咒语可能是其中最高效的

相关内容