使用shell巧妙高效的批量刪除歷史檔案或目錄
阿新 • • 發佈:2019-01-09
背景:有實時產生的資料按小時分檔案儲存,如“/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 引數設定分隔符