ARG_MAXとshell組み込みコマンド(bash)

twitterのfriend timelineのログをファイルベースでログとってたら*1、気がつくとarchiveのディレクトリに5万件超のファイルが蓄積されていました。

これだけの件数のファイル群はrmコマンドで一気に消そうとしても、消せません。

-bash-3.00$ rm *
-bash: /bin/rm: 引数リストが長すぎます

この引数リストの長さの上限はARG_MAXというマクロ定数で定義されているようです。

-bash-3.00$ getconf ARG_MAX
131072

ARG_MAXの制限により、コマンドに渡す引数が(うちの環境では)131072byteを超えてしまうと上記のエラーになってしまいます。この場合は一つのファイルが「786587805」のような名前で保存されている為、5万件超のファイルを指定する「*」のファイルグロブが展開されたファイルリストの文字列が余裕で131072byteを超えてしまいます。

xargsを使うとこの問題を回避できます。

ls | xargs rm

lsからパイプ経由で渡された引数をxargsがARG_MAXを超えないように分割して実行してくれるようです。

似たような事はfind -execでも可能ですが、この場合は1ファイルずつrmコマンドを実行することになるので対象のファイルサイズによっては実行が低速になってしまったりします。

find * -exec rm {} \;


ところで、「lsはなぜARG_MAXの制限を受けないのか?」という疑問が。


echo はシェルの内部コマンドのため ARG_MAX の制限を受けない

UNIXの部屋 コマンド検索: xargs
http://x68000.q-e-d.net/~68user/unix/pickup?xargs

なるほど、確かにechoはshellのbuiltinのようです。

-bash-3.00$ type echo
echo is a shell builtin

しかし、lsはbuiltinではない??

-bash-3.00$ type ls
ls is aliased to `ls --color=tty'

・・と思ったけど、aliasがbuiltinだからlsコマンド実行はARG_MAXの制限を受けないという事なのかな。

-bash-3.00$ help | grep alias
 alias [-p] [name[=value] ... ]     bg [job_spec]
 umask [-p] [-S] [mode]             unalias [-a] name [name ...]

もし、間違っていたらご指摘下さい。

*1:とりあえずそうしておいて、時間があるときにDB管理に作り変えようとしていました