tmpwatchで出来ることをfindで実現する

Cygwinを使っていて、/tmpに不要なファイルがたまってしまっていて、なんか上手く消せないか考えていました。思いついたのが.bashrcにtmpwatchを仕掛ける方法でしたが、やっぱfindでいいじゃんって結果になった話です。

念のためtmpwatchの擁護をしておくと、削除に特化しているので使いやすいし、RedHat系ではデフォルトで入っているようなので、ちょっとした運用で使うのにはいいと思います。日本語の解説サイトもたくさんあるしね。
古い不要ファイル・ディレクトリを削除する『tmpwatch』コマンド | 俺的備忘録 〜なんかいろいろ〜.
tmpwatchコマンドとオプション | 俺のひとり言.
tmpwatch の動作を確認する – しょぼんメモリ (´・ω・`).

というわけで、tmpwatchの機能を確認しつつ、findで代替できることを確認していきましょう。参考にするのはそれぞれのmanページです。
tmpwatch(8) – Linux man page.
Man page of FIND.
tmpwatchは日本語manページが見当たらなかった。

とりあえずtmpwatchの主な機能、削除するという機能です。findは探してリストするだけのコマンドだと思われがちだけど、削除するオプションがあります。

-delete ファイルを消去する。消去に成功すれば、真を返す。消去に失敗した場合は、 エラーメッセージを表示する。 -delete に失敗した場合の find の終了ステータスは、ゼロ以外である (最終的に終了したときの 終了ステータスのことである)。 -delete を使用すると、自動的に -depth オプションが有効になる。
情報源: Man page of FIND.

ちょっと長めに引用したけど、ここにはfindコマンドの特徴が反映されています。そう、findコマンドの引数は全て式になっています。式の結果が偽になったら次のファイルへ処理が移ります。

まずは-u、-m、-cという引数。これでtmpwatchはアクセス時刻、編集時刻、inode変更時刻のそれぞれを検査するようになります。これはfindでもそれぞれ検査できますが、動作を変更するという動きではなく、-atime、-mtime、-ctimeでそれぞれの日数を検査できます。日数では精度が悪いって場合は-amin、-mmin、-cminを使うと分単位で指定することができます。

時刻周りで言うと、findの時刻指定は+/-の符号を付けることで以上、以下を表現できます。これは時刻だけでなくサイズ等にも使うことができます。

逆にtmpwatchには-Mという、ディレクトリのみ編集時刻を使う、というオプションがあります。findには全く同じオプションはないですが、組み合わせて作ることができます。こんな感じでしょうか。
$ find /path/to/dir/ \( -type d -mtime +3 \) -o \( ! -type d -atime +3 \)
括弧をエスケープしているのはシェルで展開されるのを防ぐためです。意図通りに動くかは分かりませんが、いちおう動くようです。

面倒になってきたので-aの全て、-fの強制はいいでしょう。-dのディレクトリ除外はさっきのパターンに入ってましたね。!は否定の意味です。
$ find /path/to/dir/ ! -type d
findコマンドの-typeはファイル、ディレクトリだけでなく、シンボリックリンクやパイプ、デバイス等も判別できます。というわけで、-lのシンボリックリンク除外も簡単ですね。
$ find /path/to/dir/ ! -type l

tmpwatchは-qでメッセージを抑制できますが、findは意図して出力しないと何も出てきません。あ、でもアクション系の引数を何も指定していなかった場合はファイル名が表示されちゃいますね。なので-deleteを指定したら何も出力されません。でも、なんとしても出力を抑制したいなら/dev/nullへリダイレクトしておきましょう。

tmpwatchは-tでテスト実行することもできるみたいだけど、findにはそれもありません。でも、-delete付けないで実行すればいいだけなので、いいでしょう。むしろ-deleteなしでファイル名を出力し、本実行は-deleteを付けるとファイル名も出力されなくなる。これで十分だと思います。

そしてユーザー。tmpwatchでは-Uで指定ユーザが所有するファイルを除外することができますが、findでは除外だけでなく、指定ユーザのファイルのみをピックアップすることもできます。しかも-uidだとユーザIDなので番号しか使えませんが、-userで指定するとユーザ名すなわち名前で指定することができるのです。素晴らしい。あ、tmpwatchは元からどっちも使えるのか。

しかしfindはさらに使える。グループを指定できる-gid、-groupというオプションもあるのです。しかも-permでパーミションを検査することも可能。実行者が読み込み、書き込みが可能なファイルのみ選択する-readableと-writableなんてのもあるみたいです。

最後に指定のパスを除外する-xと-X。大文字の方はパターンで指定できるそうです。findだと-pathというのがあってパターンを指定できます。しかも-regexで正規表現を使うこともできます。

で、実はひとつ飛ばしてました。tmpwatchは-sを指定するとfuserコマンドでファイルが使用中でないか調べてくれるようです。/sbinにコマンドがないとダメっぽいので、ファイルごとにコマンド打ってるっぽいね。ならfindもできる。findは-execでコマンドを実行できます。ちょっと癖があるんだけど、特に制限はありません。-sと同じことをするならこうかな。
$ find /path/to/dir/ ! -exec fuser {} \; -print
fuserの戻り値が使用中だと0、それ以外で1だったので!で反転させています。他のコマンドも指定できるので用途は広がりますが、ファイルごとにコマンドが起動するのが玉にキズ。一括で処理する場合はxargsコマンドにパイプするのがオススメです。詳細は、また今度ね。

というわけで、長くなっちゃったけど、findは高機能なのでドンドン活用することをオススメします。でも、高機能すぎて失敗することもあるので、動作確認は入念に。