一個清理指令碼的改進思路

jeanron100發表於2015-05-29
前幾天同事問我一個問題,說在unix環境下有個目錄下的檔案/資料夾太多了,已經報了開始報系統錯誤了,客戶希望能夠定時進行這些目錄的清理。
我連到那個環境去檢視,ls都需要等待很長時間沒有反應,最後嘗試使用find命令,根據檔名來查詢的時候反應才相對要快一些。
同事計劃使用crontab來實現。
使用的命令大體如下:
59 23 1 1,4,7,10  * find /xxxx/tmp -mtime +90 -type d -print|xargs rm –rf 
其中關鍵的地方是使用了xargs,根據我之前的測試,發現xargs在大批次的檔案過濾時,效果還是不能讓人滿意的,而且在命令最後接入rm -rf,如果出現什麼紕漏,那影響可就大了。
所以開始我是不建議直接這麼用的。

根據分析,發現其實在幾個目錄下藥刪除的檔案目錄命名規則都比較固定。
比如是20141201的日誌,命名就類似下面的形式。
container-default-instanceJob-201412001_xxxxxx
其中變化的部分主要是時間的部分,所以決定使用find -name的方式效果要好一些,但是find -name結合xargs的時候如果檔案比較多,刪除的時候還是有問題,而且rm -rf的潛在隱患還是有。
一種比較直接的方式就是我們生成對應的檔案目錄名,如果匹配,則刪除,如果不匹配,也不會報出錯誤。
比方說我們根據需要刪除字2014年12月1日起某些天的記錄,則可以手工指定對應的檔名和時間戳。
rm -rf /xxxx/tmp/container-default-instanceJob-20141202*
rm -rf /xxxx/tmp/container-default-instanceJob-20141203*
rm -rf /xxxx/tmp/container-default-instanceJob-20141204*
rm -rf /xxxx/tmp/container-default-instanceJob-20141205*
rm -rf /xxxx/tmp/container-default-instanceJob-20141206*
rm -rf /xxxx/tmp/container-default-instanceJob-20141207*

這種方式會避免不少的問題,刪除速度是沒有問題的。而且可以避免很多意外的情況。
但是缺點就是太手動了,感覺沒什麼技術含量。
我們來把這個過程自動化一下。能夠動態生成對應的檔案目錄名,每次執行之後都會把基準的時間重新調整。
比如我們刪除60天的記錄,假設起始時間為20141201,則60天后就是20150130,第二次執行這個命令就會把起始時間自動調整為20150130,終止時間就是20150331了。
第一次執行命令後,生成的刪除命令為:
rm -rf /xxxx/tmp/container-default-instanceJob-20141202*
....
rm -rf /xxxx/tmp/container-default-instanceJob-20150130*

第二次執行同樣的命令,生成的刪除命令為:
rm -rf /xxxx/tmp/container-default-instanceJob-20150130*
....
rm -rf /xxxx/tmp/container-default-instanceJob-20150331*
這種方式就比較動態了,而且刪除起來也是一個很穩定的過程。

首先採用shell的形式寫了如下的指令碼。
GetIncDate()
{
 L_DAY=$1
 days=$2
 L_TODAY=$(printf "%(%Y%m%d)T\n" "${L_DAY}0000 + ${days} day")
 print ${L_TODAY}
}
 
function gen_clean_script
{
for i in {1..$duration}
do
echo 'rm -rf /xxxxx/tmp/container-default-instanceJob-'`GetIncDate $initdate $i` >> gen_clean_script.sh
done
}

這種方式基於Linux環境實現,可以靈活的使用date命令的選項進行時間的計算。
但是問題來了,在Linux下可行的方案在unix底下沒有那些個命令選項。也就是說這個shell指令碼在unix下執行不了。問題還是基於一些命令的相容性。


最後嘗試把時間的計算用sql來實現,這樣也不會存在平臺的限制。
寫出的基於sql計算時間的shell指令碼如下:

function gen_clean_script
{
conn_str=$3
print "
conn  $conn_str
set linesize 200
set serveroutput on
set feedback off
begin
for i in 1..$2 loop
dbms_output.put_line('rm -rf /xxxxx/tmp/container-default-instanceJob-'||to_char(to_date('$1','yyyymmdd')+i,'yyyymmdd')||'*');

end loop;
end;
/
" |sqlplus -s /nolog > gen_clean_script.sh

}

function get_next_date
{
conn_str=$3
print "
conn  $conn_str
set serveroutput on
set feedback off
begin
dbms_output.put_line(to_char(to_date('$1','yyyymmdd')+$2,'yyyymmdd'));

end;
/
" |sqlplus -s /nolog > init.date
}


conn_str=n1/n1@xxxx
duration=60
if [[ ! -s init.date ]] ;then
echo '***********************************************'
echo '20141201' > init.date
initdate=20141201
echo $initdate
echo '***********************************************'
else
initdate=`cat init.date`
fi

gen_clean_script $initdate $duration $conn_str
get_next_date $initdate $duration $conn_str


cat gen_clean_script.sh 
問題的解決就有了一種相對比較可行的思路,這種方案有一個缺點就是需要連線資料庫,不過對於資料庫使用者的配置沒有其它要求,只要能執行sql查詢即可。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23718752/viewspace-1677250/,如需轉載,請註明出處,否則將追究法律責任。

相關文章