1. 程式人生 > >使用shell巧妙高效的批量刪除歷史檔案或目錄

使用shell巧妙高效的批量刪除歷史檔案或目錄

背景:有實時產生的資料按小時分檔案儲存,如“/data/2013/09/18/14.txt”。現需要保留30天的最新資料,而刪除所有其它的歷史資料。注意“保留30天的最新資料”,可能不是連續的30天,中間若某一天資料缺失,也必須把最新的30天的資料保留下來。

思路:獲取所有資料路徑列表,去除最新30天的資料路徑,然後遍歷刪除。若是使用指令碼語言來開發(如php,python),迴圈獲取路徑列表的程式碼就已經比較臃腫了,效率也不高,特別是檔案目錄特多的時候。使用shell應該更方便和高效

rm -rf `find /data/*/*/*/ -type d|awk '{a[NR]=$0}END{n=asort(a,sa)-30;for(i=1;i<=n;i++){print sa[i]}}'`

詞命令還存在一個隱患,rm的引數字元長度可能超過1024的限制,修改如下

find /data/*/*/*/ -type d|awk '{a[NR]=$0}END{n=asort(a,sa)-30;for(i=1;i<=n;i++){print sa[i]}}'|xargs -I{} rm -rf {}

這個命令裡使用了find,效率還是有些不滿意,使勁的尋找更高效獲取路徑列表的方式。哈哈,黃天不負苦心人啊,終於找到一個

echo /data/*/*/*/|awk '{for(i=1;i<=NF;i++){a[i ]=$i}}END{n=asort(a,sa)-30;for(i=1;i<=n;i++){print sa[i ]}}'|xargs -I{} rm -rf {}

使用time命令測試執行速度,第二條命令和第三條命令其執行時間分別是0.007s和0.002s,後者快了3倍

但鬱悶的是,我不知道“echo /data/*/*/*/“到底是怎麼個原理,有什麼限制等等,網上也還沒有搜尋到相關資料,有知道的朋友請告知一下啊

2013-10-17 編輯補充:

原命令還可以修改精簡一下,通過指定awk使用的換行符來避免for迴圈

echo /data/*/*/*/|awk 'BEGIN{ORS=RS=" "}{a[NR]=$0}END{n=asort(a,sa)-30;for(i=1;i<=n;i++){print sa[i ]}}'|xargs -I{} rm -rf {}

還有一個問題就是,你可能想在日誌中記錄下刪除了那些檔案。可以先把檔案列表賦值給一個變數,記錄日誌後再刪除

files=`echo /data/*/*/*/|awk 'BEGIN{ORS=RS=" "}{a[NR]=$0}END{n=asort(a,sa)-30;for(i=1;i<=n;i++){print sa[i ]}}'`
echo $files; #輸出日誌
echo -e ${files//\ /"\n"}|xargs -I{} rm -rf {}
關鍵是最後一行, echo 的-e引數是為了可以輸出\n換行,如無此引數則不會識別。

${files//\ /"\n"} 是把變數files裡的所有空格都替換成\n換行符,這樣xargs才能正確切分引數。不知道為什麼會這樣


2015-4-16 繼續優化命令

files=`ls -1 -r /data/*/*/*/ | awk 'NR>=30{print $0}'`
echo $files; #輸出日誌
echo -e $files | xargs -I{} -d " " rm -rf {}

說明:

ls :  -1引數表示一個檔案或目錄單獨佔一行顯示, -r 表示按路徑降序排列(預設是升序排列)

xargs: -d 引數設定分隔符