私は素朴なことを試しています:
$ 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 {} \;
ファイルの数がcat * | sort -u
に達したときに、MAX_ARG
のより簡単なUNIXスタイルの置き換えはありますか?このような一般的なタスク用の小さなシェルスクリプトを作成するのは面倒です。
GNU sort
、およびprintf
が組み込まれているシェル(最近のpdksh
の一部のバリアントを除くすべてのPOSIXのようなもの)) :
_printf '%s\0' * | sort -u --files0-from=- > output
_
ここでの問題は、そのパイプラインの2つのコンポーネントが同時に独立して実行されるため、左側のコンポーネントが_*
_グロブを展開するまでに、右側のコンポーネントがoutput
ファイルを作成した可能性があるということですoutput
は入力ファイルと出力ファイルの両方になるため、すでに問題が発生している可能性があります(おそらく_-u
_では発生しません)。そのため、出力を別のディレクトリ(_> ../output
_たとえば)、またはグロブが出力ファイルと一致しないことを確認します。
このインスタンスでそれに対処する別の方法は、それを書くことです:
_printf '%s\0' * | sort -u --files0-from=- -o output
_
こうすることで、書き込みのためにsort
を開くoutput
となり、(私のテストでは)ファイルの完全なリストを受け取るまでは(グロブが展開された後は)実行されません)。また、読み取り可能な入力ファイルがない場合は、output
の破壊を回避します。
zsh
または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
_
printf
が組み込まれており、コマンドライン引数の制限が適用されないため、少なくともBashでは簡単な修正が機能します。
printf "%s\0" * | xargs -0 cat | sort -u > /tmp/bla.txt
(echo * | xargs
も機能しますが、空白などのファイル名の処理は例外です。)
find . -maxdepth 1 -type f ! -name ".*" -exec cat {} + | sort -u -o /path/to/sorted.txt
これにより、現在のディレクトリ内の非表示でない通常のファイルがすべて連結され、それらの結合された内容が(重複する行を削除しながら)ファイル/path/to/sorted.txt
にソートされます。
効率は相対的な用語であるため、最小化する要素を実際に指定する必要があります。 CPU、メモリ、ディスク、時間など。議論のために、メモリ使用量を最小限に抑えたいと考えており、それを実現するためにCPUサイクルをより多く費やす用意があると仮定します。 StéphaneChazelasによって提供されるようなソリューションはうまく機能します
sort -u --files0-from <(printf '%s\0' *) > ../output
しかし、彼らは個々のテキストファイルが最初から高度な一意性を持っていると想定しています。そうでない場合、つまり後の場合
sort -u < sample.txt > sample.srt
sample.srtは、sample.txtよりも10%以上小さいため、マージする前にファイル内の重複を削除することにより、メモリを大幅に節約できます。また、コマンドをチェーンしないことで、さらに多くのメモリを節約できます。つまり、異なるプロセスの結果を同時にメモリに保存する必要はありません。
find /somedir -maxdepth 1 type f -exec sort -u -o {} {} \;
sort -u --files0-from <(printf '%s\0' *) > ../output
@ilkkachuと同様ですが、cat(1)は不要です。
printf "%s\0" * | xargs -0 sort -u
また、データが非常に長い場合は、sort(1)オプション-parallel=[〜#〜] n [〜# 〜]
[〜#〜] n [〜#〜]がコンピュータのCPUの数である場合