forループで「引数が長すぎます」エラーが発生しないのはなぜですか?


9

これにより「引数が長すぎます」エラーが発生することがわかりました。

ls *.*

そして、これはそれを上げません:

for file in *.*
do
    echo $file
done

どうして?


両方の実験で同じシェルを使用しましたか?おそらく/bin/bash/bin/sh(これはおそらくダッシュへのリンクです)?
maxschlepzig

はい、私は非常に長いファイル名を持つ10000ファイルで実験を行いました。「ls *」は失敗し、「for f in *」は成功しました。
lamwaiman1988

回答:


13

「引数が長すぎます」エラーはE2BIGexecve引数(および一部のシステムでは環境)の合計サイズが大きすぎる場合にシステムコールによって発生します。このexecve呼び出しは、外部プロセスを開始するもので、具体的には異なる実行可能ファイルをロードします(fork同じ実行可能ファイルからのコードである別のプロセスを実行するための別の呼び出しがあります)。forそれが呼び出す必要としないので、ループは、内部シェル構築物ですexecve。このコマンドls *.*は、グロブが展開されたときでlsはなく、呼び出されたときにエラーを発生させます。

execveE2BIGコマンドへの引数の合計サイズがARG_MAX 制限を超えると、エラーで失敗します。次のコマンドを使用して、システムでこの制限の値を確認できますgetconf ARG_MAX。(十分なメモリがある場合は、この制限を超える可能性があります。無関係なエラーが発生しない限り機能ARG_MAXする保証を維持しexecveます。)


なぜシェルに制限がなかったのですか?
lamwaiman1988 2011

1
@ gunbuster363 execve制限はカーネルによって適用されます。引数はカーネルメモリを介して一度にコピーする必要があり、ユーザープロセスが任意の量のシェルメモリを要求することができないため、制限が適用されます。シェルの内部では、制限を設ける理由はありません。仮想メモリに収まるものであれば問題ありません。
Gilles「SO-邪悪なことをやめなさい」

5

最初の例でlsは/ ペアのシステムコールbashを介して実行され、2番目の例ではすべての動作がの内部にあると想定しています。forkexecbash

exec呼び出しは、限界があるの内部作業bashの代わりにはしていない(または、より良い、とは何の関係も持っていない別の制限があるexec、使用可能なメモリの量を多分)。


あなたはに制限を見つけることができるexecでは/usr/include/linux/limits.h通常、と定義しますARG_MAX
jw013、2011

シェルのforループを使用する場合、アイテムの大きなリストがすべてのRAMを消費すると思いますか?
lamwaiman1988 2011

この答えは間違っています。「内部」ではなく、引数とコマンドの制限が異なるだけです。
多項式

5

なぜならlsそれは引数であり、引数の数は限られているからです。

forサイクルの場合、それは単なるアイテムのリストです。(私が知る限り)制限はありません。


シェルの拡張には明らかに制限があります。これは、使用可能なRAMの容量に大きく関係します。これを試してください。私の4 GB RAMシステムは、約1,500万の8バイト引数でガスケットを吹き飛ばします:for i in {00000001..20000000} ;do ((10#$i==1)) && break; done
Peter.O

4
@fred RAMを制限として言及する必要があるとは本当に思っていませんでした。
サイモン・トス

2
必要ではないかもしれませんが、それはコメントの性質です。誰かがそれを興味深い、あるいは価値があると感じるかもしれません。
Peter.O

@fred:実際にはそうです。非常に大きな引数を展開することが一般的な問題である場合、すべてをメモリに保持せずに実装することが可能です。
Matteo
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.