500万ファイルを効率的にマージ

500万ファイルを効率的にマージ

間違った計画のため、私のディレクトリには500万を超えるファイルが含まれており、総容量は約20 GBです。各ファイルの上部には32行のゴミが含まれており、その後に不明な数の重要なデータ行があります。

すべての重要なデータを1つのファイルに統合したいと思います。

私はこれをやっています:

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

all.txtは毎秒約0.5MBだけ増加します。これを行うより速い方法はありますか?また、作業を完了する前にディスク容量が不足している可能性があるため、ファイルを削除すると便利です。 X

どんな提案にも感謝します。

答え1

いつでもファイルを削除する必要がある場合、作成した内容はすでにクイック削除方法です。 1つの最適化は、をfind使用してファイルを一覧表示するのではなく、ファイルの内容を一覧表示するために使用できることです*。これは、ファイルが追加の処理時間を発生させることなくディレクトリリストに表示されるためですfind。つまり、次のように作成します。

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

ただし、マージを完了する前にそのアイテムを削除して、どのコンテンツがどのファイルから来たかを維持したい場合は、一度に解析して複数のアイテム(シェルで許可されている限り)を追跡する方法があります。これを行うコマンドは次のとおりです。

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

最後に、一度に1つずつ複数のファイル名を一度に渡すように求められます+findこれにより、(呼び出されるインスタンスの数がはるかに少なくなるため)パフォーマンスが大幅に向上しますが、tail出力ファイルにはまだ次の内容があります。

==> ./filename <==

1つのファイルが終了し、次のファイルが起動するたびに印刷します。また、これらのファイルは削除されません。

少しの速度を犠牲にして上記の行を削除するには、次のように実行できます。

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

(コメントで提案してくれたdave_thompsonに感謝します)。

最後に、どの情報がどのファイルから来たのかを一覧表示する出力を好み、いつでも削除したい場合は、iruvarの答えを使用して2つの「」を「」\;+に置き換えることができます(私の元の答えは何をすべきか?を提供します。

答え2

プロセスがIOバインディングになる可能性があるため、最適化ループはせいぜいわずかな改善をもたらすでしょう。ファイルに対して深度優先操作を実行できる場合と、tail呼び出しrmをメディアにローリング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システムでは、複数のファイルを受信したときにファイルヘッダーの印刷を抑制する-qためにtoに渡すこともできます。tailtail

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

注 - この-exec rm最後-deleteのマントラはおそらく最も効率的です。

関連情報