2008年4月7日 星期一

find 指令 time 選項及 xargs 一起使用

今天看了一下catchall的mailbox, 有9萬多封郵件, 我的postfix是以directory方式儲存郵件,每個郵件都是一個檔案, 開次一打開這個資料夾都很慢, 所以想按日期分類, 減少單一資料夾的檔案數.

我的catchall是以IMAP連接dovecot的式, 需要先create 一些按日期的資料夾, 以2008-01, 2008-02, ...的分類成式, 由於每個用也有兩萬封, 還是太多, 所以再在每個月裡create 01-10, 11-20, 11-31資料夾, 按日分類, 兩這些資料夾的實際path是在catchall Maildir/.INBOX.2008-01.01-10, Maildir/.INBOX.2008-01.11-20, ...把郵件按日期move到這些folder裡的new或cur即可(dovecot會在IMAP登入時把郵件從new移到cur).

但catchall inbox的郵件太多, 執行ls等指令很慢, 單用mv 及 rm等指令一次也不能處理太多檔案. 其中一個辦法是以find找到想移動的檔案再用xargs送到mv處理, find 能處理的檔案很多, 但好像也有限(至少9萬個處理不了, 會直接停止執行), 所以find的使用要有點技巧.

find的功能很多, 這次要以郵件檔的modification time來判斷它到達server的時間, 所以要用mtime選項(因為ctime在移動後會改為移動的時間, 所以執行第二次已經不能判斷).

find . -mtime n 當中 . 為目前路徑搜尋, n 為數字, 代表多少個24小時. mtime default是以當前時間的n*24小時計算, 如果想要以當日的24:00作基準(實際是向未來的時間方向移動,即明日的00:00的n*24小時計算),需要加上-daystart參數.

n 的數值為 0 時代表現在到24小時前之間, 加上daystart代表現在到今天00:00之間
n 的數值為 1 時代表24小時前到48小時前之間, 加上daystart代表今天00:00到昨天00:00之間(即整個昨天)
n 還可以加+或-, 分別代表1(24小時前到48小時前的時段)的兩邊, 但不包括1, 即-1代表現在(理論上是無限的未來)到24小時前的時段, +1代表48小時及之前(理論上是無限的過去)的時段. -0應該沒有任何結果, 除非有未來建做的檔案存在, 有這樣的檔案應該是電腦的時間調校錯了.
之外mtime可以組會使用, 如:
find . -mtime +1 -mtime -3 這裡指48小時前及未到72小時之間, 相當於 -mtime 2.

了解mtime的用法後回到剛才的一個問題上, find遇到超出數量時也不能運作, 所以在我那個有9萬個files的folder上使用時需要些技巧, 經我測試發覺組合的mtime是由左至右執行,例如我想找48小時前至72小時前之間的files, 需要用 -mtime +1 及 -mtime -3, 如果是:

find . -mtime +1 -mtime -3 這樣會先執行 +1 , 即所有48小時前的檔案, 以我的情況是至少有8萬多個, 一段時間後自動跳出執行, 沒有結果. 相反:

find . -mtime -3 -mtime +1 這樣會先執行 -3, 現在至72小時前之間, 有幾千, 沒有超出限量, 跟著再以 +1把現在至48小時前之間的除去, 得到我想要的結果.

以find 找到檔案後要送給xargs再執行mv:
find . -mtime -3 -time +1 | xargs -i mv {} destination.
當中 -i 代表用{}代表前面送來的結果(這裡即find的結果), {}代表find的結果, 並作為mv的source, destination代表目標路徑.
除了-i外可以用 -I, 差別是-I可以指定代表結果的字完, 如:
xargs -i mv {} /tmp
相當於:
xargs -I [] mv [] /tmp

最後成功把emails按日期分類.