web-dev-qa-db-ja.com

引用符で囲まれた引数を渡すときに「/ bin / sh:引数リストが長すぎる」と表示されるのはなぜですか?

sh -c ''に渡すことができるコマンドラインはどれくらい長くできますか? (bashおよびbourne Shell)

この制限は、OSの制限よりもはるかに低くなっています(最新のLinuxの場合)。

例えば:

$ /bin/true $(seq 1 100000)
$ /bin/sh -c "/bin/true $(seq 1 100000)"
bash: /bin/sh: Argument list too long

そして、どうすればこの問題を回避できますか?

更新

getconfはここでは役に立ちません(システムの制限ではないため)。

$ seq 1 100000 | wc -c
588895
$ getconf ARG_MAX
2097152

アップデート#2

ここで何が重要なのか理解しました。これはシェルの制限ではなく、システムの制限ですが、引数リスト全体ではなく、各引数の長さに対するものです。

$ /bin/true $(seq 1 100000)
$ /bin/true "$(seq 1 100000)"
bash: /bin/true: Argument list too long

説明をありがとう、CodeGnome。

25
Igor Chubin

TL; DR

単一の引数は、MAX_ARG_STRLENより短くする必要があります。

分析

このリンク によると:

また、2.6.23以降の追加の制限として、1つの引数はMAX_ARG_STRLEN(131072)より長くすることはできません。これは、「sh -c '生成された長い引数'」のような長い呼び出しを生成する場合に関連する可能性があります。

これはまさに、OPによって特定された「問題」です。許可される引数の数は非常に大きくなる可能性があります(getconf ARG_MAX)、引用符で囲まれたコマンドを/ bin/shに渡すと、シェルは引用符で囲まれたコマンドを単一の文字列として解釈します。 OPの例では、MAX_ARG_STRLENの制限を超えるのはこの単一の文字列であり、拡張された引数リストの長さではありません。

実装固有

引数の制限は実装固有です。ただし、 このLinux Journalの記事 は、システム制限の増加など、それらを回避するいくつかの方法を提案しています。これはOPに直接適用できない場合がありますが、それでも一般的な場合には役立ちます。

他に何かをする

OPの問題は実際には実際の問題ではありません。問題は、現実の問題を解決しない任意の制約を課すことです。

ループを使用すると、これを簡単に回避できます。たとえば、Bash 4の場合:

for i in {1..100000}; do /bin/sh -c "/bin/true $i"; done

正常に動作します。ループを通過するたびにプロセスを生成するので、確かに遅くなりますが、発生しているコマンドライン制限を確実に回避できます。

あなたの本当の問題を説明してください

ループで問題が解決しない場合は、質問を更新して、本当に長い引数リストを使用して実際に解決しようとしている問題を説明してください。任意の行の長さの制限を調査することは学術的な課題であり、Stack Overflowのトピックではありません。

22
Todd A. Jacobs

そのエラーメッセージは表示されません。私の秘密?単一引用符:

/bin/sh -c '/bin/true $(seq 1 100000)'

二重引用符を使用すると、すべてのシェルでそのエラーが発生します。

$ /bin/sh -c "/bin/true $(seq 1 100000)"
-bash: /bin/sh: Argument list too long
$ /bin/bash -c "/bin/true $(seq 1 100000)"
-bash: /bin/bash: Argument list too long
$ /bin/ksh -c "/bin/true $(seq 1 100000)"
-bash: /bin/ksh: Argument list too long
$ /bin/zsh -c "/bin/true $(seq 1 100000)"
-bash: /bin/zsh: Argument list too long

コマンドの実行に使用されているシェルに関係なく、Bashがエラー「-bash:...」を発行しているという事実からわかるように、二重引用符が使用されている場合、引数リストは現在のシェルで展開されます。ちなみに私のシステムでは、shはDashです。

これは他の「ホスト」シェルにも当てはまります。

$ dash
$ /bin/bash -c '/bin/true $(seq 1 100000)'
$ /bin/bash -c "/bin/true $(seq 1 100000)"
dash: /bin/bash: Argument list too long

患者:医師、これを行うと痛い」
博士:それをしないでください。

エラーが発生しなくなるまで100,000を減らします。

/bin/sh -c "/bin/true $(seq 1 99999)"
/bin/sh -c "/bin/true $(seq 1 99998)"

等.

0
chepner

最初の行として#!/bin/shを使用してファイルを作成し、コマンドの残りの部分を後続の行に配置しますか? :)

さらに真剣に、-sオプションを使用してSTDINからコマンドを読み取ることができるため、長いコマンドラインを生成して/bin/sh -sにパイプすることができます。

0
dannysauer

私のOSでは、二分法によって得られる最大長です

/bin/sh -c "/bin/true $(Perl -e 'print"a"x131061')"

だから131071

しかし、長い間ラインを持つ理由はありません。引数の数が多い場合は、代わりに「$ @」を使用できます。例えば

/bin/sh -c 'command "$@"' -- arg1 arg2 .. argn
0