4.10.2012

Using the '–mtime' option in the 'find' command

UNIX: find –mtime コマンドについて

あるディレクトリ配下でn日間更新されていないファイルを削除する場合、などのケースで
「find」コマンドの「-mtime」オプションを使うのは古来からある由緒正しき方法である。

例えばこのように。

find target -mtime +7 |xargs rm -f

このとき、n日前に更新されたファイルは削除されるのか?
やや直感的でない部分があるので整理しておく。

man ページを見たところ、処理のポイントは以下2点である。

1. 「-mtime」で得られる数値

まず、検査対象のファイルそれぞれに対して「find コマンドが実行された時刻」から「ファイルの最終更新時刻」が差し引かれた値(秒単位)が求められる。
そして、それが何日分に相当するかが算出される。
このとき 1日に満たない時間は切り捨てられる。(よって結果は必ず整数となる)

例えば、1秒前に更新されたファイルなら「0」、ちょうど3日前(3*24*60*60=259,200秒前)に更新されたファイルなら「3」、
その1秒後(現在から259,199秒前)に更新されたファイルなら「2」となる。

2. 数値の比較

そして、パラメータとして指定された値と比較される。ここで符号は次のように解釈される。

  +   : 指定された値より大きい場合にマッチ
符号なし: 指定された値と一致する場合のみマッチ
  -   : 指定された値より小さい場合にマッチ

例えば、符号を付けずに「-mtime 3」と指定した場合は上記の1.の計算結果が「3」のものだけが
find コマンドの結果として得られることとなる。
「-mtime -3」であれば「2」以下のものが、「-mtime +3」であれば「4」以上のものが抽出される。

従って、コマンドの結果は以下の図のようになる。(図で白い丸は端点を含まないこと、黒い丸は端点を含むことを表す)

image

一般に、「-mtime +n」と指定した場合、最終更新時刻がちょうど(n+1)日前よりも古いファイルが抽出される。
(秒単位でちょうど(n+1)日前のものも含む)

・実機での確認 (Solaris 11)

 ファイルの状態と現在時刻

$ ls -l
total 4
-rw-r--r-- 1 mog staff 0 2012-04-03 00:00 04030000.txt
-rw-r--r-- 1 mog staff 0 2012-04-04 00:00 04040000.txt
-rw-r--r-- 1 mog staff 0 2012-04-05 00:00 04050000.txt
-rw-r--r-- 1 mog staff 0 2012-04-06 00:00 04060000.txt
-rw-r--r-- 1 mog staff 0 2012-04-07 00:00 04070000.txt
-rw-r--r-- 1 mog staff 0 2012-04-08 00:00 04080000.txt
-rw-r--r-- 1 mog staff 0 2012-04-09 00:00 04090000.txt
-rw-r--r-- 1 mog staff 0 2012-04-10 00:00 04100000.txt
$ date
2012年04月09日 (月) 23時48分58秒 JST
$

 find コマンド実行結果

$ find *.txt -mtime +3 -ls
   235    1 -rw-r--r--   1 mog      staff           0  4月  3 00:00 04030000.txt
   234    1 -rw-r--r--   1 mog      staff           0  4月  4 00:00 04040000.txt
   184    1 -rw-r--r--   1 mog      staff           0  4月  5 00:00 04050000.txt
$ find *.txt -mtime 3 -ls
   183    1 -rw-r--r--   1 mog      staff           0  4月  6 00:00 04060000.txt
$ find *.txt -mtime -3 -ls
   134    1 -rw-r--r--   1 mog      staff           0  4月  7 00:00 04070000.txt
   186    1 -rw-r--r--   1 mog      staff           0  4月  8 00:00 04080000.txt
   190    1 -rw-r--r--   1 mog      staff           0  4月  9 00:00 04090000.txt
   198    1 -rw-r--r--   1 mog      staff           0  4月 10 00:00 04100000.txt
$

・ソースコードの確認 (OpenSolarisの場合)

 find コマンド開始時刻の取得

     if (time(&now) == (time_t)(-1)) {
        (void) fprintf(stderr, gettext("%s: time() %s\n"),
            cmdname, strerror(errno));
        exit(1);
    }

 ファイルの最終更新時刻との差分算出

        case MTIME:
             t = statb->st_mtime;
        days:
            l = (now-t)/A_DAY;
            goto num;

 結果の比較

        num:
            if (np->second.i == '+')
                val = (l > np->first.l);
            else if (np->second.i == '-')
                val = (l < np->first.l);
            else
                val = (l == np->first.l);
            break;

・未来の更新日時のファイル

最後に、やや特殊な例であるがファイルの更新日時が find コマンドの実行時刻よりも新しい場合も考えられる。
実装はカーネルに依存する部分も多いが、それらはマイナス値として正しく判定されるよう工夫がなされているようだ。

参考:
OpenSolaris の find コマンドのソース
http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/find/

GNU project 'findutils'
http://ftp.gnu.org/pub/gnu/findutils/

0 件のコメント:

コメントを投稿