大容量テキストファイルを効率的にマージ/ソート/ユニーク

大容量テキストファイルを効率的にマージ/ソート/ユニーク

無邪気な努力をしています。

$ cat * | sort -u > /tmp/bla.txt

失敗:

-bash: /bin/cat: Argument list too long

したがって、(巨大な一時ファイルの生成)などの愚かな解決策を避けるには、次のようにします。

$ find . -type f -exec cat {} >> /tmp/unsorted.txt \;
$ cat /tmp/unsorted.txt | sort -u > /tmp/bla.txt

次のようにファイルを1つずつ処理できます(これにより、メモリ消費量が減り、ストリーミングメカニズムに近づきます)。

$ cat proc.sh
#!/bin/sh
old=/tmp/old.txt
tmp=/tmp/tmp.txt
cat $old "$1" | sort -u > $tmp
mv $tmp $old

以下は次のとおりです。

$ touch /tmp/old.txt
$ find . -type f -exec /tmp/proc.sh {} \;

もっとシンプルでUnixスタイルの代替案はありますか?cat * | sort -uファイル数に達したときMAX_ARG?これらの一般的な操作のために小さなシェルスクリプトを書くのは厄介です。

答え1

少なくともBashでは動作する簡単な修正です。printf組み込みであり、コマンドライン引数制限が適用されないためです。

printf "%s\0" * | xargs -0 cat | sort -u > /tmp/bla.txt

echo * | xargsスペースなどを含むファイル名を処理する以外は機能します。)

答え2

GNUsortと組み込みシェルの使用printf(現在、いくつかのバリエーションを除くすべてのPOSIX様シェルpdksh):

printf '%s\0' * | sort -u --files0-from=- > output

1つの問題は、このパイプラインの2つのコンポーネントが同時に独立して実行されるため、左側のコンポーネントがglobを拡張したときに*右側のコンポーネントがすでにoutputファイルを作成している可能性があることです-uoutput入力ファイルは出力ファイルなので、出力を別のディレクトリ(> ../output例:)に移動するか、globが出力ファイルと一致しないことを確認する必要があります。

この場合、問題を解決する別の方法は、次のように書くことです。

printf '%s\0' * | sort -u --files0-from=- -o output

これは書き込み用にsort開きますがoutput(私のテストでは)ファイル全体のリストを受け取るまで(グローブが拡張されてから長い時間が経過してから)機能しません。outputまた、読み取り可能な入力ファイルがない場合でも破損を防ぎます。

それを書くもう一つの方法はzshorで書くことです。bash

sort -u --files0-from=<(printf '%s\0' *) -o output

これはプロセスオーバーライドを使用して行われます(ここで、<(...)オーバーライドはprintf書き込まれるパイプの読み取りの終わりを参照するファイルパスで置き換えられます)。この関数kshはから来ましたが、ksh個々の引数を<(...)コマンドに拡張する必要があるため、構文と一緒に使用することはできません--option=<(...)。ただし、次の構文を使用できます。

sort -u --files0-from <(printf '%s\0' *) -o output

catファイルが改行で終わらない場合は、ファイルに提供された出力に対する他のアプローチを見ることができます。

$ printf a > a
$ printf b > b
$ printf '%s\0' a b | sort -u --files0-from=-
a
b
$ printf '%s\0' a b | xargs -r0 cat | sort -u
ab

また、sortソートはロケール()の照合順序アルゴリズムを使用して実行され、strcollate()バイトsort -uレベルの一意の行ではなく、そのアルゴリズムでソートされた各行セットの1つを報告します。バイトレベルで一意の行だけに興味があり、ソート順序についてはあまり気にしない場合は、ソートがバイト値に基づいてCでロケールを変更することをお勧めします(memcmp();これにより、速度が速くなる可能性があります。状況が大幅に向上しました):

printf '%s\0' * | LC_ALL=C sort -u --files0-from=- -o output

答え3

find . -maxdepth 1 -type f ! -name ".*" -exec cat {} + | sort -u -o /path/to/sorted.txt

これにより、現在のディレクトリに隠されていないすべての一般ファイルをリンクし、結合された内容を(重複行を削除しながら)ファイルにソートします/path/to/sorted.txt

答え4

@ilkkachuに似ていますが、cat(1)は必要ありません。

printf "%s\0" * | xargs -0 sort -u

また、データが非常に長い場合は、 sort(1) オプションを使用することをお勧めします。 - 平行線=窒素

いつ窒素コンピュータのCPU数。

関連情報