コマンドラインで作業をしていると、特に大量のファイルやディレクトリを扱う際に「argument list too long」というエラーに直面することがあります。
このエラーは、システムが扱える引数の上限を超えた場合に発生します。
その原因と対処法について解説します。
エラーの原因
コマンドラインでコマンドに引数を渡す際、例えばls dir1
のように記述します。
ここでdir1
が引数となりますが、引数の数がシステムの許容上限を超えると「argument list too long」エラーが発生します。
この上限値はgetconf ARG_MAX
コマンドで確認でき、多くの環境では約2MBと設定されています。
この値はシステムのコンパイル時に定められるため、動的に変更することはできません。
試しに確認してみると、
|
|
手元の環境では2MBでした。
この問題が発生する時は大体がワイルドカードを使用したコマンドを実行した時だと思います。
|
|
ワイルドカードを使用すると、シェルが展開を行いls dir*
コマンドは下記のように置き換えられます。
|
|
もしdirディレクトリが100万個あったとすると、先ほどの上限は軽く超えてしまうためargument list too longエラーとなってしまいます。
対処方法その1 xargsコマンドの使用
大量のファイルやディレクトリを扱う場合、xargsコマンドが非常に有効です。
xargsは標準入力から受け取ったデータを元に、指定したコマンドの引数として渡して実行することができます。
例えば、以下のように使用します。
|
|
xargsの動作は簡単に以下の流れになります。
- 標準入力から読み込んだ文字列を指定したコマンド(例だとls)の引数として与え作成する
- 作成したコマンドを実行する
上記例の場合は下記のコマンドを作成してくれます。
|
|
ですが、このままではまたargument list too longが起きるのでは?と思ってしまいますが、xargsはシステムが定めているコマンドラインの長さの限界に達するまで、長いものが作成される仕様となっているため、argument list too longエラーは発生しません。
つまり限界が来たら下記のように複数回のコマンド実行に置き換えられます。
|
|
ちなみにxargsのコマンドラインの限界の長さは--show-limits
オプションで確認できます。
|
|
6行目のSize of command buffer we are actually usingの項目がそれで手元の環境では約130kとなっていました。
システムの限界が2MBだったのに130kとなっているのはsオプションを指定しない場合のデフォルト値が130kになっているからです。
試しにsオプションで2MBを指定してみると変更されることが分かります。
|
|
ところで、getconf ARG_MAX
コマンドで取得した上限は2MBでした。
ではこの上限を超えた値、例えば3MBを指定するとどうなるのでしょうか。
答えは上限に補正される、です。
試しに指定してみると2MBとなり、上限に補正されていることが分かります。
|
|
xargsの動作を実際に確認してみよう
xargs
の利便性は分かってもテストしないと怖くて実行できないと思います。
ここではテスト環境を作成して実際に確認してみることにしましょう。
テスト環境を作成する
それではテスト環境を作成して実際にxargsコマンドの動作確認をしてみましょう。
ここではディレクトリが1000個、各ディレクトリにファイルが100個あるケースで実際にやってみることにします。
まずはテストケースのディレクトリとファイルを作成します。
今回はtestディレクトリに環境を作成することにしました。
|
|
何やら4行目で早速xargsを使っていますが、この例では既にargument list too longが発生する状態のため使用せざるを得ません。
ここで使用しているIオプションは標準入力から渡される文字列を任意の場所に埋め込みたい場合に使用します。
xargs ls
のように、何も指定しないとlsの後ろにしか追加されないため、コマンドの指定の位置に埋め込みたい場合はIオプションを使用します。
この場合では{}
はdir0001に置き換えられることになり実際は、
touch dir0001/file{001..100}.txt dir0002/file{001..100}.txt ...省略
という形になります。
置き換える文字列に{}
を使っていますがaaa
やbbb
といった任意の文字列が使えます。ただし基本的に{}
を使うことになっており、混乱を避けるためにも特に理由がなければ{}
を使うことをお勧めします。
argument list too longを発生させてみる
少し話がそれましたが、テスト環境でargument list too longが発生するか確認してみましょう。
|
|
全ての*.txtファイルを取得しようとするとargument list too longが発生しました。
ちゃんと上限を超えているようですね。
.txtファイルを一つずつ取得してみる
では次に各ディレクトリの.txtファイルを一つずつ取得してみましょう。
|
|
lsコマンドの結果をファイルに出力し行数を数えるとちゃんと10万行1になっている事が分かります。
これで大量のファイルを一つずつ処理できることが確認できましたが、実際に実行されるコマンドを事前に確認したいことがあると思います。
その場合はpオプションを使用します。
|
|
実行するととてつもなく長いコマンドが表示された後に?...
と表示され入力待ちになります。
ここでy
またはY
を入力すると表示されたコマンドが実行され、そのままenterを押下するとスキップされて次のコマンドが表示されるようになっています。
特に削除するようなコマンドを実行する時はpオプションを指定して、想定した引数になっているか確認してから実行するようにしましょう。
実際に削除してみる
ここまで確認できれば大量ファイルの削除は簡単です。
各ディレクトリのfile001.txt~file080.txtを削除してみましょう。
まずは念のため、まとめて削除できないことを確認してみます。
|
|
やはりエラーが出て削除できませんね。
ファイル数が多すぎるようです。
では一つずつファイルを取得してxargsに削除コマンドを作成してもらい実行する形にしてみます。
今回はテストのためpオプションなしで確認せずに一気に削除します。
|
|
削除後に確認してみるとfile001.txt~file080.txtがちゃんと削除されていることが分かります。
対処方法その2. findコマンドの-execオプションの使用
xargs
の代わりに、find
コマンドの-exec
オプションを使用しても同様の問題を解決できます。
-exec
オプションを利用すると、find
が見つけた各ファイルに対して直接コマンドを実行することができます。
|
|
上記は下記のようなイメージになります。
|
|
こちらでもargument list too longのエラーは回避できますが、一つ一つのファイルに対してコマンドを実行することになりxargs
と比べるとかなり非効率です。
ですが、まとめてファイルを処理する必要がないケースではxargs
と比べてfind
と-exec
オプションを使用した方が簡潔に記載できるメリットがあります。
例えば下記のようなケースではfind
と-exec
オプションの組み合わせが有効です。
1. 特定のファイルを見つけて削除する
特定の拡張子を持つファイルを探して削除する必要がある場合、-exec
オプションを使用すると、見つかった各ファイルに対して直接rm
コマンドを実行できます。
|
|
このコマンドは/path/to/directory
内の.tmp
拡張子を持つすべてのファイルを検索し、それぞれを削除します。
xargs
を使用するよりも直接的で、シンプルなタスクに対してはより読みやすい解決策です。
2. ファイルに対して特定のコマンドを実行する
見つけたファイルに対してコマンドを実行する必要がある場合、例えばファイルのパーミッションを変更する場合、-exec
オプションを使うことで、各ファイルに対して直接chmod
コマンドを実行できます。
|
|
3. 複数のコマンドを連鎖させる
-exec
オプションを使用すると、見つけたファイルに対して複数のコマンドを連鎖させて実行することも可能です。
例えば、特定のファイルを見つけて内容を表示した後に削除する場合、以下のように記述できます。
|
|
このコマンドは、.log
ファイルを検索し、それぞれの内容を表示(cat
)した後に削除(rm
)します。
この方法は、複数のステップを一つのコマンドライン操作で実行したい場合に有効です。
まとめ
argument list too long
エラーは、コマンドラインで大量のファイルを扱う際によく遭遇する問題です。
しかし、xargs
やfind
の-exec
オプションを適切に使用することで、この問題を回避しつつ作業を効率化することが可能です。
さらに詳しい情報やオプションについては、各コマンドのマニュアルを参照してください。
JM Project find
JM Project xargs
実行環境
|
|
↓↓↓下記はアフィリンクです↓↓↓
ハードウェアスタートアップ企業のお話です。
ほのぼのとした世界観でとても読みやすいので息抜きに是非。
途中まで無料で読めます。
-
100001となっているのは最後の改行によるもの ↩︎