posts - 188,comments - 176,trackbacks - 0

          在編寫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子目錄已經存在)

          #!/bin/sh
          sqlldr_dir=`pwd`
          sqlldr_data_dir
          ="data"

          cd 
          $sqlldr_dir/$sqlldr_data_dir
          rm 
          -*.txt

          對于上面代碼,當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操作加上異常保護。代碼如下:

          #!/bin/sh
          sqlldr_dir=/home/coner/blackall
          sqlldr_data_dir
          ="data"

          cd 
          $sqlldr_dir/$sqlldr_data_dir >/dev/null 2>&1
          if [ $? -ne 0 ]
               then 
                    echo 
          "the path of $sqlldr_dir/$sqlldr_data_dir invalid.."
                    
          exit  
               
          else
                    echo 
          "begin rm -f $sqlldr_dir/$sqlldr_data_dir/*.txt"
                    rm 
          -*.txt
          fi

          或者在能確定路徑的情況下直接寫成定值: 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)沒有關系,即使在腳本中進行下面的初始化操作:

          # if HP-UX and AIX
          if [ -/home/zxin10/.profile ]
           then
                    echo 
          "INIT profile TO UNIX"
                    
          . /home/zxin10/.profile
          fi
          # if Linux
          if [ -/home/zxin10/.bash_profile ]
                     then
                    echo 
          "INIT bash_profile TO LINUX"
                     
          . /home/zxin10/.bash_profile
          fi

          在用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這樣的形式。

          上面是我個人的實踐和理解,歡迎大家提出好的建議,共同參考學習。



          posted on 2008-05-18 17:18 cheng 閱讀(3266) 評論(0)  編輯  收藏 所屬分類: Unix/Linux
          主站蜘蛛池模板: 资兴市| 富宁县| 外汇| 申扎县| 贡觉县| 论坛| 浏阳市| 夹江县| 鹤庆县| 获嘉县| 荥经县| 肥城市| 中牟县| 福州市| 上虞市| 锡林郭勒盟| 汉中市| 古浪县| 铅山县| 潼南县| 抚远县| 星座| 罗田县| 天津市| 天峻县| 高要市| 咸阳市| 定日县| 信丰县| 志丹县| 呼伦贝尔市| 安仁县| 江川县| 延边| 安溪县| 湖州市| 岳阳县| 延长县| 黄陵县| 内江市| 天等县|