「xargs 引数行が長すぎます」エラーの調査と解決策

JavaScriptを有効にしてください

まえがき

コマンドラインで非常に長い単一の引数を扱うとき、以下のようなエラーが発生する場合があります。

1
2
3
xargs: command line cannot be assembled, too long
# または日本語環境では
xargs: 引数行が長すぎます

今回は、このエラーの原因を詳しく調査し、解決方法を紹介します。

なぜエラーが起きるのか?

xargs は、システムが受け付けられる引数長の制限(ARG_MAX)を超えないように自動的に引数を分割します。しかし、次のような場合には分割ができずエラーになります。

  • 単一の非常に長い引数(空白や改行で区切られていない文字列)を渡している
  • システムの設定上のバッファサイズを超えている

調査方法

1. システムのARG_MAXを調べる

まずはシステムで許容される引数の最大サイズを調べます。

1
$ getconf ARG_MAX
1
2097152

この例では、約2MBが引数の長さの上限です。

さらに、xargsが実際に使用している内部のバッファサイズは次のように調べられます。

1
$ xargs --show-limits < /dev/null
1
2
3
...省略
実際に使用しているコマンドバッファの大きさ: 131072
...省略

ここでは131072バイト(128KB)が実際の上限になっています。

実際のエラーの原因を調査する方法

例えば以下のコマンドでエラーが出たとします。

1
$ printf 'A%.0s' {1..131067} | xargs echo
1
xargs: 引数行が長すぎます

この出力のバイト数を調べるには次のようにします。

1
$ printf 'A%.0s' {1..131067} | wc -c
1
131067

echoというコマンド名やスペース、終端文字(ヌル文字)も含めると、この場合は131072バイトの制限を超え、エラーになります。

エラー回避策

単一の長い引数を扱うため、一般的な引数の分割方法(-nfind -execなど)は使えません。エラーを回避する方法としては以下の方法があります。

固定長で分割してコマンド側で対処する(foldを利用)

もし引数を分割しても問題ない場合は、foldコマンドで固定長に分割する方法があります。

1
printf 'A%.0s' {1..500000} | fold -w50000 | xargs -I{} echo {}

こうすると、50000文字ずつに分割され、それぞれを別々に処理できます。

バッファサイズの拡張(-s)で制限を回避できるのでは?

xargsはsオプションでバッファサイズをARG_MAXの上限(例:2MB)に拡張できますが、残念ながらxargsのコマンドで回避できてもexecで引っかかります。

1
printf 'A%.0s' {1..500000} | xargs -s 2000000 echo
1
xargs: 引数の長さ制限により exec() を呼び出すことができません

ARG_MAX, maximum length of arguments for a new process の「Number of arguments and maximum length of one argument」セクションに記載の通り、下記の制約があるようです。

追加の制限として、1つの引数は MAX_ARG_STRLEN (131072) を超えてはならないというルールがあります。
自動生成した引数の多いコマンドを "sh -c ‘…’" のように呼び出す場合、ここで問題が起きる可能性があります。

単一の長い引数をどうしても扱いたい場合の結論

どうしても分割したくない非常に長い単一の文字列を渡したい場合は、引数を分割した上で、それを受け取るコマンド側で工夫して対処する方法を検討する必要があります。

今回のような問題に直面した場合は、分割の可否を見極めて適切な方法を選択しましょう。


スポンサーリンク

共有

もふもふ

プロフィール

著者
もふもふ
プログラマ。汎用系→ゲームエンジニア→Webエンジニア→QAエンジニア