crontab

Crontab問題總結

crontab如果不注意的話早晚會出問題,而且這種問題一旦出一次,就會永遠記得,因爲這種問題很折騰人。
                                                                                                          ——某前輩

設置了一個crontab
30 0 * * * cd /home/work/user/huangbx/research/getfeature/data/current; sh resample.sh &>/dev/null
$sh resample.sh是可以運行的
$head -5 resample.sh
##對事實數據進行採樣
set -x
g_date=`date -d "3 days ago " +%Y%m%d`
可是放到crontab裏面就無法運行了。
從網上瞭解到一般crontab無法運行的問題都是由環境變量在crontab中不一定可識別引起的。可是resample.sh中並沒有涉及環境變量的使用。
經過多番嘗試,終於發現是代碼的第一行的中文註釋引起的問題,添加上#!/bin/sh後就可以運行了。
總結了一下:
crontab中必須十分注意環境變量的使用
#!/bin/sh並不是必須,只是當沒有sha-bang的時候,也不要在第一行有"#"後帶的中文註釋!!
最好當然是加上sha-bang啦 #!/bin/sh
2008-11-3補充:
之前沒有特別注意環境變量引起的crontab失敗,今天果然就遇到了。
問題描述:cron了某sh文件,裏面執行多個操作,既調用了外部的shell腳本,也調用了外部的python腳本。從運行日誌看,發現部分腳本被調用,而部分python腳本沒有被調用。沒有被調用的均是python腳本,而且均使用了MySQLdb模塊(第三方模塊)。
該腳本在平時直接使用sh命令均可以正常執行。
出錯信息:
Traceback (most recent call last):
File "areafile.py", line 2, in <module>
    import MySQLdb
File "build/bdist.linux-x86_64/egg/MySQLdb/__init__.py", line 19, in <module>
File "build/bdist.linux-x86_64/egg/_mysql.py", line 7, in <module>
File "build/bdist.linux-x86_64/egg/_mysql.py", line 6, in __bootstrap__
ImportError: libmysqlclient.so.15: cannot open shared object file: No such file or directory
MySQLdb需要調用mysql這個庫,可是系統並不知道你的mysql安裝在哪裏 : (
問題解決:
在總控的shell腳本中添加一句話
export LD_LIBRARY_PATH=/home/work/local/mysql5/lib/mysql
(也就是來自~/.bash_profile中的LD_LIBRARY_PATH字段)後程序終於可以在crontab中正常啓動。
解釋:
1) ~/.bash_profile && ~/.bashrc
用戶登陸Linux操作系統的時候,"/etc/profile", "~/.bash_profile"等配置文件會被自動執行。執行過程是這樣的:登陸Linux系統時,首先啓動"/etc/profile",然後啓動用戶目錄下的"~/.bash_profile",如果"~/.bash_login"和"~/.profile"文件存在的時候也會在執行"~/.bash_profile"後被依次調用。
下面看看"~/.bash_profile"文件裏面有什麼東西
$cat ~/.bash_profile
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/bin:/home/work/local/python/lib/python2.5/site-packages/django/bin/:$HOME/bin:/home/work/local/mysql5/bin/;
LD_LIBRARY_PATH=/home/work/local/mysql5/lib/mysql
alias py='/home/work/local/python/bin/python'
export PATH LD_LIBRARY_PATH
unset USERNAME
可以看到~/.bash_profile文件先調用~/.bashrc,然後再把PATH和LD_LIBRARY_PATH加載。
.bash_profile和.bashrc的差別
/etc/profile:此文件爲系統的每個用戶設置環境信息,當用戶第一次登錄時,該文件被執行.
並從/etc/profile.d目錄的設置文件中搜集shell的設置.
/etc/bashrc:爲每一個運行bash shell的用戶執行此文件.當bash shell被打開時,該文件被讀取.
~/.bash_profile:每個用戶都可使用該文件輸入專用於自己使用的shell信息,當用戶登錄時,該
文件僅僅執行一次!默認情況下,他設置一些環境變量,執行用戶的.bashrc文件.
~/.bashrc:該文件包含專用於你的bash shell的bash信息,當登錄時及每次打開新的shell時,該
該文件被讀取.
~/.bash_logout:當每次退出系統(退出bash shell)時,執行該文件.
/etc/profile是全局性的功能,其中設置的變量作用於所有用戶,~/.bash_profile中設置的變量能繼承/etc/profile中的變量並作用於用戶。
~/.bash_profile 是交互式、login 方式進入 bash 運行的
~/.bashrc 是交互式 non-login 方式進入 bash 運行的
通常二者設置大致相同,所以通常前者會調用後者。(http://blog.chinaunix.net/u2/63775/showart_527708.html )
可是在運行crontab的時候,是non_login方式調用程序的,此時~/.bash_profile並不會被提前調用。所以,crontab的運行環境相對於login方式進入bash運行的環境來說小得多。如果程序涉及~/.bash_profile使用的環境變量,那麼,部分在login方式可以正常運行的程序在crontab下就無法運行。
在我的程序中,系統無法識別MySQLdb,於是解決方案就是在總控的shell腳本中添加這樣一句:
export LD_LIBRARY_PATH=/home/work/local/mysql5/lib/mysql
更加推薦的解決方案:
在cron中加入
LD_LIBRARY_PATH=/home/work/local/mysql5/lib/mysql
這樣cron中所有使用mysql的東東都可以順利運行了 : ) 而且這樣可以使得操作更加清晰。
終極推薦解決方案:
30 12 * * * source ~/.bashrc && cd /home/work/mydir && ./myproj
2) LD_LIBRARY_PATH
Linux運行時有一套共享庫(*.so)。共享庫的尋找和加載是通過/lib/ld.so (RunTime Shared Library Loader)完成的。ld.so在標準路徑(/lib, /usr/lib)下尋找共享庫。可是如果第三方庫並非安裝在標準路徑下,程序運行的時候就會出現無法找到庫的錯誤,類似於下面這個報錯
ld.so.1: curl: fatal: libgcc_s.so.1: open failed: No such file or directory
通過設置環境變量LD_LIBRARY_PATH可以讓ld.so尋找非標準路徑的共享庫。LD_LIBRARY_PATH中可以設置多個路徑,路徑之間通過冒號":"分割。LD_LIBRARY_PATH中的路徑先於標準路徑的查找。
在~/.bash_profile中添加如下代碼(比如把mysql的so文件添加進LD_LIBRARY_PATH)
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/work/local/mysql5/lib/mysql
export LD_LIBRARY_PATH
由於~/.bash_profile在用戶登陸時會加載(而且僅加載)一次,然後ld.so就會在標準路徑和LD_LIBRARY_PATH中自動尋找和加載共享庫。
LD_LIBRARY_PATH的缺點:(參考http://xahlee.org/UnixResource_dir/_/ldpath.html)
"For security reasons, LD_LIBRARY_PATH is ignored at runtime for executables that have their setuid or setgid bit set. This severely limits the usefulness of LD_LIBRARY_PATH." ... .... ....."LD_LIBRARY_PATH is one of those insidious things that once it gets set globally for a user, things tend to happen which cause people to rely on it being set. Eventually when LD_LIBRARY_PATH needs to be changed or removed, mass breakage will occur!" ... ... ......"Nowadays you specify the run-time path for an executable at link stage with the -R (or sometimes -rpath) flag to ld. There's also LD_RUN_PATH which is an environment variable which acts to ld just like specifying -R. Before all this you had only -L, which applied not only during compile-time, but during run time as well. There was no way to say “use this directory during compile time” but “use this other directory at run time”. There were some rather spectacular failure modes that one could get in to because of this. "
文中同時給出瞭如何合理使用LD_LIBRARY_PATH:(雖然沒有完全看懂,還是貼一下,期待不久的將來能看懂)
      1) Never ever set LD_LIBRARY_PATH globally.
            If you must ship binaries that use shared libraries and want to allow your clients to install the program outside a 'standard' location, do one of the following:
            Ship your binaries as .o files, and as part of the install process relink them with the correct installation library path.
             Ship executables with a very long “dummy” run-time library path, and as part of the install process use a binary editor to substitute the correct install library path in the executable.
        2) If you are forced to set LD_LIBRARY_PATH, do so only as part of a wrapper.
       3). Remove the link-time aspect of LD_LIBRARY_PATH.....It would be much cleaner if LD_LIBRARY_PATH only had influence at run-time. If necessary, invent some other environment variable for the job (LD_LINK_PATH).
3) ld.so.conf
除了設置LD_LIBRARY_PATH外,還可以設置/etc/ld.so.conf。然後運行ldconfig生成ld.so.cache。ld.so查找公共庫的時候也會從ld.so.cache中查找。
不過http://xahlee.org/UnixResource_dir/_/ldpath.html還是猛烈批判了ld.so.conf的設置。
"Some OS's (e.g. Linux) have a configurable loader. You can configure what run-time paths to look in by modifying /etc/ld.so.conf. This is almost as bad a LD_LIBRARY_PATH! Install scripts should never modify this file! This file should contain only the standard library locations as shipped with the OS. "
LD_LIBRARY_PATH的runtime Linker詳細行爲可以參考http://docs.sun.com/app/docs/doc/819-0690/chapter6-63352?a=view


轉自:http://hi.baidu.com/huangboxiang/blog/item/f798a7dc3eb096e877c63833.html

 

大家都知道crontab是個好東東,可以定時執行一些任務,幫助你監控系統狀況,幫助你每天重複的做一些機械的事情。但是crontab有一個壞毛病,就是它總是不會缺省的從用戶profile文件中讀取環境變量參數,經常導致在手工執行某個腳本時是成功的,但是到crontab中試圖讓它定期執行時就是會出錯
原先我用一個很傻的辦法,就是在腳本中直接指定所有的環境變量參數,每次寫腳本都要寫好多好多PATH啦,LD_LIBRARY_PATH之類的環境變量參數
後來發現其實可以直接在腳本里先執行一下用戶的profile文件,就OK了
如果是Linux環境下的腳本,腳本的頭上用缺省的#!/bin/sh就可以了,如果是Solaris環境下的腳本,腳本頭上用#!/bin/ksh
然後第一個部分先寫這些:
###################
. /etc/profile
. ~/.bash_profile
##################
這樣,crontab在執行腳本的時候,就能夠讀到用戶的環境變量參數啦。。。一點兒小技巧而已 ^_^
附:
如果你是在cron裏提交的,請注意:
不要假定c r o n知道所需要的特殊環境,它其實並不知道。所以你要保證在s h e l l腳本中提供所有必要的路徑和環境變量,除了一些自動設置的全局變量。
如果c r o n不能運行相應的腳本,用戶將會收到一個郵件說明其中的原因。

修改ldd snort的指定共享庫


在命令行下輸入env命令,顯示所有的環境變量,找到其中的LD_LIBRARY_PATH=/usr/local/lib:/usr/local/eversec/mysql/lib該行

然後執行export LD_LIBRARY_PATH=/usr/lib:$LD_LIBRARY_PATH,暫時修改LD_LIBRARY_PATH環境變量

所有用戶修改是在/etc/profile文件中修改export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/eversec/mysql/lib

修改某用戶是在某用戶當前目錄下的bash_profile文件:~/.bash_profile文件添加export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/eversec/mysql/lib該行


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章