「引数リストが長すぎます」:コマンドを変更せずにどのように処理しますか?


18

のようなコマンドを実行するとls */*/*/*/*.jpg、エラーが発生します

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

これが起こる理由はわかっています。それは、コマンドへの引数のためのスペースの量にカーネルの制限があるためです。標準的なアドバイスは、使用するコマンドを変更して、引数に非常に多くのスペースを必要としないようにすることです(たとえば、findandを使用xargs)。

コマンドを変更したくない場合はどうすればよいですか?同じコマンドを使い続けたい場合はどうすればよいですか?このエラーを取得せずに、「機能する」ようにするにはどうすればよいですか?どのソリューションが利用可能ですか?


便利な読書:Bashのよくある質問95。コマンドを変更しないと、再コンパイルして引数リストの最大サイズを大きくしたり、ディレクトリ構造を変更してファイルが少なくなる以外にできることはあまりありません。
jw013

1
Linuxカーネルバージョンに基づいた@ jw013では、引数リストを増やすことができる場合があります。最近のシステムの変更の詳細については、unix.stackexchange.com / a / 45161/8979を参照してください。
ウルリッヒダンゲル

@UlrichDangel、うん、それは可能です!私の答えをご覧ください。私の答えは、それを行う方法を示しています(Linuxで、十分な最近のカーネルを使用)。
DW

回答:


26

Linuxでは、コマンド引数の最大容量は使用可能なスタック容量の1/4です。したがって、解決策は、スタックに使用できるスペースの量を増やすことです。

ショートバージョン:次のようなものを実行します

ulimit -s 65536

長いバージョン:スタックに使用可能なデフォルトの容量は8192 KB程度です。次のように、使用可能なスペースの量を確認できます。

$ ulimit -s
8192

より大きな数を選択し、スタックに使用可能なスペースの量を設定します。たとえば、スタックに最大65536 KBを許可する場合は、次を実行します。

$ ulimit -s 65536

試行錯誤を使用して、これがどれだけの大きさであるかを試してみる必要があるかもしれません。多くの場合、これはの構文からコマンドや作業を変更する必要がなくなります間に合わせと-ソリューションであるfindxargs(私はそうすることに他の利点があるものの実現)など、。

これはLinux固有のものだと思います。おそらく、他のUnixオペレーティングシステム(テストされていない)では役に立たないでしょう。


1
次のように機能したことを確認できます。$ getconf ARG_MAX 2097152 $ ulimit -s 65535 $ getconf ARG_MAX 16776960
Alex

2

このLinux Journalの記事では、4つのソリューションを紹介しています。4番目の解決策だけが、コマンドの変更を必要としません。

方法4では、コマンドライン引数用にカーネル内で割り当てられるページ数を手動で増やす必要があります。include / linux / binfmts.hファイルを見ると、上部近くに次のものがあります。

/*
 * MAX_ARG_PAGES defines the number of pages allocated for   arguments
 * and envelope for the new program. 32 should suffice, this gives
 * a maximum env+arg of 128kB w/4KB pages!
 */
#define MAX_ARG_PAGES 32

コマンドライン引数専用のメモリ量を増やすには、MAX_ARG_PAGESの値を大きくする必要があります。この編集が保存されたら、通常どおりに新しいカーネルを再コンパイル、インストール、再起動します。

独自のテストシステムで、この値を64に上げることで、すべての問題を解決することができました。広範なテストの後、切り替え以来、単一の問題は発生していません。MAX_ARG_PAGES64に設定しても、作成できる最長のコマンドラインはシステムメモリを256KBしか占有しないため、これは完全に予想されたものであり、今日のシステムハードウェア標準ではそれほど多くありません。

方法#4の利点は明らかです。これで、通常どおりコマンドを簡単に実行できるようになり、正常に完了します。欠点も同様に明らかです。コマンドラインで使用可能なメモリの量を使用可能なシステムメモリの量を超えて増やすと、自分のシステムでDOS攻撃を作成してクラッシュさせることができます。特にマルチユーザーシステムでは、すべてのユーザーに追加のメモリが割り当てられるため、わずかな増加でも大きな影響を与える可能性があります。そのため、方法#4が実行可能なオプションであるかどうかを判断する最も安全な方法であるため、常に独自の環境で広範囲にテストしてください。

私はこの制限が非常に迷惑であることに同意します。


1

の代わりにls */*/*/*/*.jpg試してください:

echo */*/*/*/*.jpg | xargs ls

xargs(1)システム上の引数の最大数を知っており、その制限を超えない引数で、指定されたコマンドラインを複数回呼び出すために標準入力を分割します(それよりも低く設定することもできます)-nオプションを使用したOSの最大値)。

たとえば、制限が3つの引数であり、5つのファイルがあるとします。その場合xargsls2回実行されます。

  1. ls 1.jpg 2.jpg 3.jpg
  2. ls 4.jpg 5.jpg

多くの場合、これは完全に適しているが、常にではない-たとえば、あなたがに頼ることができないls(1)並べ替えそれぞれ独立しているため、適切にあなたのためのすべてのエントリをls-invocationがによってそれに与えられたエントリのソートサブセットだけでしょうxargs

他の人が提案したように制限を引き上げることはできますが、制限はまだあります-そしていつかあなたのJPGコレクションは再びそれを超えます。無限数に対処するためにスクリプトを準備する必要があります...


アイデアをありがとう!これは悪い回避策ではありません。2つの注意点:1.これは、名前にスペースが含まれるディレクトリとファイル名で壊れるため、完全な代替ではありません。2. シェル組み込みコマンドではないシェルで、の代わりにで同じ問題Argument list too longが発生しますか?(多分それはほとんどのシェルで問題ではないので、おそらくそれは無関係です。)echolsecho
DW

1
はい、ファイル名の特殊文字は問題です。あなたの最善の策はfind-print0述語で使用することです-そして、その出力xargs-0オプションでパイプします。 echoは組み込みのシェルであり、exec(3)のコマンドラインの制限を受けません。
ミハイルT.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.