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管理に作り変えようとしていました