在編寫shell腳本的時候,有時候需要在執行完shell腳本(手工執行或利用crontab定時執行),需要服務器上制定目錄下的文件或子目錄進行刪除操作,以免下次執行時產生數據沖突。 現需要編寫一個shell腳本,完成以下功能: [1]從系統B那邊將指定目錄下的文本文件FTP到系統A本地服務器的制定目錄下。 [2]FTP到本地后,執行系統A本地上的shell腳本,將文本文件中的信息入到系統A本地映射的數據庫中。 [3]入庫完畢后,再FTP到系統B將遠程的0指定目錄下的那個文本文件刪除。 [4]系統A上shell將其本地的相關目錄下的文文本件和子目錄的內容刪除,防止下次執行產生數據重復和沖突。 注:系統A和B都是HP-Unix,且系統A上的shell_a和系統B上的shell_b執行時間為每天晚上23:00之后,它們時間差大概十分鐘(如 在23:00時刻執行shell_b,到23:10時刻執行shell_a)。 上面步驟當中涉及到刪除操作的有[3]和[4],而問題就發生在第[4]步。第[4]步中的刪除系統A本地上目錄下的文件,這里我是用rm來進行刪除的。首先我的shell腳本部署在系統A的:/home/coner/blackall/目錄下,名稱為black_all.sh。 腳本中對于刪除本地文件的代碼如下(注:blackall目錄下的data 和 ctl子目錄已經存在)
對于上面代碼,當shell腳本手工執行的時候,結果沒有任何問題,sqlldr_dir的值此時為腳本所在的路徑:/home/coner/blackall/,故cd $sqlldr_dir/$sqlldr_data_dir可以成功登錄到/home/coner/blackall/data下,再進行rm -f *將data子目錄下的所有文件刪除(文件不分前綴和后綴名)。但對于定時任務,要用crontab部署的情況下呢? 問題就出在這里,筆者測試,利用crontab將該shell部署后,設置定時時間,到點后通過重定向生成的日志中,看到sqlldr_dir打印到日志中的值并不是/home/coner/blackall/,而是/home/coner。故可以推斷到,上面的刪除代碼,當用定時任務部署的時候,$sqlldr_dir/$sqlldr_data_dir的值就為/home/coner/data,而在系統A上/home/coner目錄下沒有此目錄,即cd 操作失敗,系統拋出異常(及時碰巧有這個目錄data,也是誤刪除文件的操作)。接著執行下面的rm -f *。此時,crontab命令對于該shell腳本所在位置的解析為/home/coner,故在執行rm -f *的時候就將/home/coner目錄下的所有文件全部刪除掉了,這樣就造成誤刪除文件的惡果。 郁悶+揪心中...不過幸運的是,執行腳本前有做手工的文件備份。 鑒于上面情況,筆者將shell腳本重新進行了審核,將sqlldr_dir=`pwd`換成sqlldr_dir=/home/coner/blackall,并對cd操作加上異常保護。代碼如下:
或者在能確定路徑的情況下直接寫成定值: rm -f /home/coner/blackall/data/*.txt 對于crontab命令執行定時任務,和登錄系統后,在用戶coner下手工執行shell是有區別的。前者在執行腳本時候,解析pwd命令只能解析到當前用戶即coner目錄為止,即上面的sqlldr_dir的值為/home/coner,而在用戶coner下手工執行shell是在解析pwd命令時可以正常解析到/home/coner/blackall。這個和shell腳本初始化.profile(Unix)或.bash_profile(Linux)沒有關系,即使在腳本中進行下面的初始化操作:
在用crontab執行腳本時,解釋pwd的時候,sqlldr_dir的值還是/home/coner。 上面的初始化腳本,主要是針對利用crontab部署定時任務時,因為crontab啟動的命令并不讀當前的.profile,因此所有的程序需要的環境變量需要用程序或shell自己去設置(和手工執行shell不同,手工執行shell是在某個登錄用戶下執行的,登錄該用戶之后,就已經初始化了環境變量配置文件),那么在shell中調用第三方軟件的一些命令(如Oracle的sqlplus和sqlldr等命令)時,如果程序中直接寫成sqlplus或sqlldr命令來調用時,腳本是識別不到這些命令的。在定時任務執行完畢后的系統郵件(mail命令查看)中會提示找不到該命令。解決方法就是在執行shell腳本的業務邏輯前先初始化操作系統的環境變量配置文件.profile或.bash_profile。如果不初始化也可以,那么在shell中調用這些命令時,需要將其寫成絕對路徑,如:/home/oracle/oracle92/bin/sqlldr這樣的形式。 上面是我個人的實踐和理解,歡迎大家提出好的建議,共同參考學習。