私のディレクトリには約500万のテキストファイルがあります。すべて同じ形式です(特別なものはなく、1行に整数を含むプレーンテキストファイルのみがあります)。これらすべてのファイルの最大行と最小行数を計算したいと思います。
まず、次のようにすべての行番号を作成してみました。 (その後、このリストで最小値と最大値を見つける方法を練習しました。)
wc -l `find /some/data/dir/with/text/files/ -type f` > report.txt
しかし、これによりエラーが発生しました。
bash: /usr/bin/wc: Argument list too long
たぶん、この問題を解決するより良い方法がありますか?
たぶんGNU-Parallelはここで助けることができますか?
答え1
これを使用してfind
ファイルのリストを作成し、引き続きパイピングできます。これにより、シェルが単一のコマンドで500万のファイル名をすべて拡張しようとするのを防ぎます。
LC_ALL=C find -type f -exec wc -l {} + |
awk '
$2 != "total" {
if (max=="" || $1>max) {max=$1; mxf=$2};
if (min=="" || $1<min) {min=$1; mnf=$2};
}
END { printf "Min %d for %s, max %d for %s\n", min, mnf, max, mxf }
'
find
リストを作成するファイル名の計算awk
、スクリプトに渡されます。これは順番に最大値と最小値だけでなく、ファイル名を見つけて報告するのも難しい作業です。
この単純なコードは、スペースや印刷できない文字を含むファイル名を処理しません。
答え2
最新バージョンのGNUユーティリティを使用してください。
(
printf '/dev/null\0' # for the case where's there's only one file
find . -type f -print0
) |
wc --files0-from=- -l |
sed '1d;$d' | # remove /dev/null and total
sort -n |
sed '1b;$b;d'
ここでは、引数を渡すのではなく、ファイルのリストをfind
stdinからstdinにパイプするので、いくつかの利点があります。システムコールを使用しないため、引数の数に制限はありません。ファイルが見つかったら、そのファイルを読み取ることができます。 orソリューションと比較すると、1回の呼び出しのみが実行されるため、最大1行を取得します。wc
wc
execve()
wc
find
xargs
-exec {} +
wc
total
GNU wc
8.30は、少なくとも改行文字を含むファイル名を区切ります。たとえば、名前付きファイルは次./a<newline>b
のようにレンダリングされます'./a'$'\n''b'
(ここではksh93スタイルの$'...'
引用符を使用して改行文字をとして表します$'\n'
)。この場合、wc
すべてのファイルパスがで終わるまで、変更が行われた時期がわかります.
。したがって、が表示されている場合は、'
外観の変更が行われたことを意味します。
パラメータ拡張フラグをzsh
使用して、シェルからこの操作をキャンセルできます。Q
$ wc -l './a
b'
146 './a'$'\n''b'
$ !! | read -r length file
$ printf '<%s>\n' $file ${(Q)file}
<'./a'$'\n''b'>
<./a
b>
通常、これらの損傷がいつ発生するのかわかりませんwc
。たとえば、同じファイル名a<newline>b
またはファイル名がレンダリングされます。'a'$'\n''b'
$ wc -l 'a
b' "'a'$'\n''b'"
146 'a'$'\n''b'
1 'a'$'\n''b'
147 total
答え3
xargs
これは正確な状況を処理するために存在し、関連するファイル名にスペースや改行が含まれていない限り機能します。
find /some/data/dir/with/text/files/ -type f -print | xargs wc -l
その後、行数に基づいてソートできます。どの特定のファイルに最小行数と最大行数が含まれているかを気にしない場合は、各出力行から行数フィールドを抽出してパイプライン化し、最初の行が最小行数のuniq
出力ファイルを生成できます。行、最後に行が最大行数です。
もちろん、これはあなたが探している情報を計算する過程で多くのデータを保持するので、パイプラインの出力を各行を実行してから、行ごとに数があるかどうかを追跡するスクリプトにリンクすることをお勧めしますfind | xargs
。awk
これまでに見た最小値より小さいか、これまでに見た最大値より大きいです。