web-dev-qa-db-ja.com

引数リストがlsに対して長すぎます

多くのファイルを含むディレクトリをls *.txt | wc -lしようとすると、次のエラーが発生します。

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

この「引数リスト」のしきい値は、ディストリビューションまたはコンピューターの仕様に依存しますか?通常、私はそのような大きな結果の結果を他のいくつかのコマンド(たとえば、wc -l)にパイプします。そのため、端末の制限は関係ありません。

51
user19016

エラーメッセージが長すぎる引数リストls *.txt

この制限は、バイナリプログラムとカーネルの両方にとって安全です。詳細、およびその使用方法と計算方法については、 ARG_MAX、新しいプロセスの引数の最大長 を参照してください。

パイプサイズにそのような制限はありません。したがって、次のコマンドを発行するだけです。

find -type f -name '*.txt'  | wc -l

注意:最近のLinuxでは、ファイル名に含まれる奇妙な文字(改行など)はlsfindなどのツールでエスケープされますが、*****からは表示されます。古いUnixを使用している場合は、このコマンドが必要になります

find -type f -name '*.txt' -exec echo \;  | wc -l

NB2:名前に改行を含むファイルを作成する方法を知りたいと思っていました。トリックを知っていれば、それほど難しくありません。

touch "hello
world"
53
Coren

それは主にLinuxカーネルのバージョンに依存します。

実行すると、システムの制限を確認できるはずです。

getconf ARG_MAX

これは、シェルによって展開された後のコマンドラインの最大バイト数を示します。

Linux <2.6.23では、制限は通常128 KBです。

Linux> = 2.6.25では、制限は128 KB、またはスタックサイズの1/4(ulimit -sを参照)のいずれか大きい方です。

詳細は execve(2)man page を参照してください。


残念ながら、制限はシェルではなくオペレーティングシステムにあるため、ls *.txtをパイプしても問題は解決しません。

シェルは*.txtを展開してから、

exec("ls", "a.txt", "b.txt", ...)

また、*.txtに一致するファイルが多すぎるため、128 KBの制限を超えています。

あなたは次のようなことをしなければならないでしょう

find . -maxdepth 1 -name "*.txt" | wc -l

代わりに。

(改行を含むファイル名については、以下のShawn J. Goffのコメントを参照してください。)

11
Mikel

別の回避策:

ls | grep -c '\.txt$'

lsは、ls *.txtが生成する(または生成しようとする)よりも多くの出力を生成しますが、anyを渡していないため、「引数が長すぎます」の問題には遭遇しませんlsへの引数。 grepは、ファイルマッチングパターンではなく正規表現を使用することに注意してください。

あなたは使いたいかもしれません:

ls -U | grep -c '\.txt$'

(お使いのバージョンのlsがこのオプションをサポートしていると想定しています)。これは、lsに出力をソートしないように指示します。これにより、時間とメモリの両方を節約できます。この場合、ファイルを数えるだけなので、順序は関係ありません。通常、出力のソートに費やされるリソースは重要ではありませんが、この場合、非常に多数の*.txtファイルがあることがわかっています。

また、1つのディレクトリに多くのファイルが存在しないように、ファイルを再編成することを検討する必要があります。これは可能かもしれませんし、可能でないかもしれません。

9
Keith Thompson

MAX_ARG_PAGESはカーネルパラメータのようです。 findxargsを使用することは、この制限に対処するための一般的な組み合わせですが、wcで機能するかどうかはわかりません。

find . -name \*\.txtの出力をファイルにパイプし、そのファイルの行を数えると、回避策として機能します。

1
Bram

これは汚いかもしれませんが、私のニーズと私の能力の範囲内で機能します。私はそれが非常に速く機能するとは思わないが、私の一日を続けることができた。

ls | grep jpg | <something>

90,000のjpgの長いリストを取得し、それらをavconvにパイプしてタイムラプスを生成していました。

以前はls * .jpgを使用していました|この問題に遭遇する前にavconv。

1