#事件
find /path/to/dir/ -type f -mtime +13 | xargs rm
こんなコマンドを cron に仕込んで、一定日数以上経過した古いファイルを削除していました。
今回この処理がコケていたので原因を調べてみると……
find で発見したファイルに半角スペースが含まれていました。
"/path/to/dir/hogehoge huga.txt" というファイルがおりました。
rm /path/to/dir/hogehoge huga.txt
というコマンドを実行するとどうなるかというと、/path/to/dir/hogehoge と huga.txt をそれぞれ削除しようと試みます。
意図としては rm "/path/to/dir/hogehoge huga.txt"
ということがしたいのですが、たまたま名前が似ている別のファイルが処理対象になってしまいます。
試してみる
ファイルを4つ用意。
[user@host workdir]$ ll
合計 0
-rw-rw-r-- 1 user axis 0 7月 13 16:29 2016 dump_afjspace importantfile.txt
-rw-rw-r-- 1 user axis 0 7月 13 16:28 2016 dump_fjai4fao43j9a4.txt
-rw-rw-r-- 1 user axis 0 7月 13 16:27 2016 importantfile.txt
-rw-rw-r-- 1 user axis 0 7月 13 16:27 2016 textfile.txt
名前が dump_ で始まるファイルがどれか一覧して……
[user@host workdir]$ find ./ -name "dump_*"
./dump_afjspace importantfile.txt
./dump_fjai4fao43j9a4.txt
じゃあそれを rm で消しますね。エンター押下。
[user@host workdir]$ find ./ -name "dump_*" | xargs rm
rm: cannot remove `./dump_afjspace': そのようなファイルやディレクトリはありません
え…?
[user@host workdir]$ ll
合計 0
-rw-rw-r-- 1 user axis 0 7月 13 16:29 2016 dump_afjspace importantfile.txt
-rw-rw-r-- 1 user axis 0 7月 13 16:27 2016 textfile.txt
うわぁぁ...... importantfile.txt
が消えてる。
対策
find の -exec では上記の現象は起こりません。
[user@host workdir]$ find ./ -name "dump_*" -exec rm {} \;
[user@host workdir]$ ll
合計 0
-rw-rw-r-- 1 user axis 0 7月 13 16:32 2016 importantfile.txt
-rw-rw-r-- 1 user axis 0 7月 13 16:27 2016 textfile.txt
また、 find のオプションに -print0 を付けてファイル列挙時の区切り文字を半角スペースではなく \0 で出力し、 xargs 側でもオプション -0 によって区切り文字を \0 と認識させて拾うことで、問題を回避できます。これは若干めんどくさい。
[user@host workdir]$ find ./ -name "dump_*" -print0
./dump_afjspace important.txt./dump_fjai4fao43j9a4.txt[user@host workdir]$
[user@host workdir]$ find ./ -name "dump_*" -print0 | xargs -0 rm