crontab环境变量
為什么80%的碼農(nóng)都做不了架構(gòu)師?>>> ??
設(shè)置了一個(gè)crontab
30 0 * * * cd /home/work/user/huangbx/research/getfeature/data/current; sh resample.sh &>/dev/null
$sh resample.sh是可以運(yùn)行的
$head -5 resample.sh
##對事實(shí)數(shù)據(jù)進(jìn)行采樣
set -x
g_date=`date -d "3 days ago " +%Y%m%d`
可是放到crontab里面就無法運(yùn)行了。
從網(wǎng)上了解到一般crontab無法運(yùn)行的問題都是由環(huán)境變量在crontab中不一定可識別引起的。可是resample.sh中并沒有涉及環(huán)境變量的使用。
經(jīng)過多番嘗試,終于發(fā)現(xiàn)是代碼的第一行的中文注釋引起的問題,添加上#!/bin/sh后就可以運(yùn)行了。
總結(jié)了一下:
crontab中必須十分注意環(huán)境變量的使用
#!/bin/sh并不是必須,只是當(dāng)沒有sha-bang的時(shí)候,也不要在第一行有"#"后帶的中文注釋!!
最好當(dāng)然是加上sha-bang啦 #!/bin/sh
2008-11-3補(bǔ)充:
之前沒有特別注意環(huán)境變量引起的crontab失敗,今天果然就遇到了。
問題描述:cron了某sh文件,里面執(zhí)行多個(gè)操作,既調(diào)用了外部的shell腳本,也調(diào)用了外部的python腳本。從運(yùn)行日志看,發(fā)現(xiàn)部分腳本被調(diào)用,而部分python腳本沒有被調(diào)用。沒有被調(diào)用的均是python腳本,而且均使用了MySQLdb模塊(第三方模塊)。
該腳本在平時(shí)直接使用sh命令均可以正常執(zhí)行。
出錯(cuò)信息:
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需要調(diào)用mysql這個(gè)庫,可是系統(tǒng)并不知道你的mysql安裝在哪里 : (
問題解決:
在總控的shell腳本中添加一句話
export LD_LIBRARY_PATH=/home/work/local/mysql5/lib/mysql
(也就是來自~/.bash_profile中的LD_LIBRARY_PATH字段)后程序終于可以在crontab中正常啟動。
解釋:
1) ~/.bash_profile && ~/.bashrc
用戶登陸Linux操作系統(tǒng)的時(shí)候,"/etc/profile", "~/.bash_profile"等配置文件會被自動執(zhí)行。執(zhí)行過程是這樣的:登陸Linux系統(tǒng)時(shí),首先啟動"/etc/profile",然后啟動用戶目錄下的"~/.bash_profile",如果"~/.bash_login"和"~/.profile"文件存在的時(shí)候也會在執(zhí)行"~/.bash_profile"后被依次調(diào)用。
下面看看"~/.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文件先調(diào)用~/.bashrc,然后再把PATH和LD_LIBRARY_PATH加載。
.bash_profile和.bashrc的差別
/etc/profile:此文件為系統(tǒng)的每個(gè)用戶設(shè)置環(huán)境信息,當(dāng)用戶第一次登錄時(shí),該文件被執(zhí)行.
并從/etc/profile.d目錄的設(shè)置文件中搜集shell的設(shè)置.
/etc/bashrc:為每一個(gè)運(yùn)行bash shell的用戶執(zhí)行此文件.當(dāng)bash shell被打開時(shí),該文件被讀取.
~/.bash_profile:每個(gè)用戶都可使用該文件輸入專用于自己使用的shell信息,當(dāng)用戶登錄時(shí),該
文件僅僅執(zhí)行一次!默認(rèn)情況下,他設(shè)置一些環(huán)境變量,執(zhí)行用戶的.bashrc文件.
~/.bashrc:該文件包含專用于你的bash shell的bash信息,當(dāng)?shù)卿洉r(shí)及每次打開新的shell時(shí),該
該文件被讀取.
~/.bash_logout:當(dāng)每次退出系統(tǒng)(退出bash shell)時(shí),執(zhí)行該文件.
/etc/profile是全局性的功能,其中設(shè)置的變量作用于所有用戶,~/.bash_profile中設(shè)置的變量能繼承/etc/profile中的變量并作用于用戶。
~/.bash_profile 是交互式、login 方式進(jìn)入 bash 運(yùn)行的
~/.bashrc 是交互式 non-login 方式進(jìn)入 bash 運(yùn)行的
通常二者設(shè)置大致相同,所以通常前者會調(diào)用后者。(http://blog.chinaunix.net/u2/63775/showart_527708.html )
可是在運(yùn)行crontab的時(shí)候,是non_login方式調(diào)用程序的,此時(shí)~/.bash_profile并不會被提前調(diào)用。所以,crontab的運(yùn)行環(huán)境相對于login方式進(jìn)入bash運(yùn)行的環(huán)境來說小得多。如果程序涉及~/.bash_profile使用的環(huán)境變量,那么,部分在login方式可以正常運(yùn)行的程序在crontab下就無法運(yùn)行。
在我的程序中,系統(tǒng)無法識別MySQLdb,于是解決方案就是在總控的shell腳本中添加這樣一句:
export LD_LIBRARY_PATH=/home/work/local/mysql5/lib/mysql
更加推薦的解決方案:
在cron中加入
LD_LIBRARY_PATH=/home/work/local/mysql5/lib/mysql
這樣cron中所有使用mysql的東東都可以順利運(yùn)行了 : ) 而且這樣可以使得操作更加清晰。
終極推薦解決方案:
30 12 * * * source ~/.bashrc && cd /home/work/mydir && ./myproj
2) LD_LIBRARY_PATH
Linux運(yùn)行時(shí)有一套共享庫(*.so)。共享庫的尋找和加載是通過/lib/ld.so (RunTime Shared Library Loader)完成的。ld.so在標(biāo)準(zhǔn)路徑(/lib, /usr/lib)下尋找共享庫。可是如果第三方庫并非安裝在標(biāo)準(zhǔn)路徑下,程序運(yùn)行的時(shí)候就會出現(xiàn)無法找到庫的錯(cuò)誤,類似于下面這個(gè)報(bào)錯(cuò)
ld.so.1: curl: fatal: libgcc_s.so.1: open failed: No such file or directory
通過設(shè)置環(huán)境變量LD_LIBRARY_PATH可以讓ld.so尋找非標(biāo)準(zhǔn)路徑的共享庫。LD_LIBRARY_PATH中可以設(shè)置多個(gè)路徑,路徑之間通過冒號":"分割。LD_LIBRARY_PATH中的路徑先于標(biāo)準(zhǔn)路徑的查找。
在~/.bash_profile中添加如下代碼(比如把mysql的so文件添加進(jìn)LD_LIBRARY_PATH)
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/work/local/mysql5/lib/mysql
export LD_LIBRARY_PATH
由于~/.bash_profile在用戶登陸時(shí)會加載(而且僅加載)一次,然后ld.so就會在標(biāo)準(zhǔn)路徑和LD_LIBRARY_PATH中自動尋找和加載共享庫。
LD_LIBRARY_PATH的缺點(diǎn):(參考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. "
文中同時(shí)給出了如何合理使用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
除了設(shè)置LD_LIBRARY_PATH外,還可以設(shè)置/etc/ld.so.conf。然后運(yùn)行l(wèi)dconfig生成ld.so.cache。ld.so查找公共庫的時(shí)候也會從ld.so.cache中查找。
不過http://xahlee.org/UnixResource_dir/_/ldpath.html還是猛烈批判了ld.so.conf的設(shè)置。
"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詳細(xì)行為可以參考http://docs.sun.com/app/docs/doc/819-0690/chapter6-63352?a=view
轉(zhuǎn)自:http://hi.baidu.com/huangboxiang/blog/item/f798a7dc3eb096e877c63833.html
大家都知道crontab是個(gè)好東東,可以定時(shí)執(zhí)行一些任務(wù),幫助你監(jiān)控系統(tǒng)狀況,幫助你每天重復(fù)的做一些機(jī)械的事情。但是crontab有一個(gè)壞毛病,就是它總是不會缺省的從用戶profile文件中讀取環(huán)境變量參數(shù),經(jīng)常導(dǎo)致在手工執(zhí)行某個(gè)腳本時(shí)是成功的,但是到crontab中試圖讓它定期執(zhí)行時(shí)就是會出錯(cuò)
原先我用一個(gè)很傻的辦法,就是在腳本中直接指定所有的環(huán)境變量參數(shù),每次寫腳本都要寫好多好多PATH啦,LD_LIBRARY_PATH之類的環(huán)境變量參數(shù)
后來發(fā)現(xiàn)其實(shí)可以直接在腳本里先執(zhí)行一下用戶的profile文件,就OK了
如果是Linux環(huán)境下的腳本,腳本的頭上用缺省的#!/bin/sh就可以了,如果是Solaris環(huán)境下的腳本,腳本頭上用#!/bin/ksh
然后第一個(gè)部分先寫這些:
###################
. /etc/profile
. ~/.bash_profile
##################
這樣,crontab在執(zhí)行腳本的時(shí)候,就能夠讀到用戶的環(huán)境變量參數(shù)啦。。。一點(diǎn)兒小技巧而已 ^_^
附:
如果你是在cron里提交的,請注意:
不要假定c r o n知道所需要的特殊環(huán)境,它其實(shí)并不知道。所以你要保證在s h e l l腳本中提供所有必要的路徑和環(huán)境變量,除了一些自動設(shè)置的全局變量。
如果c r o n不能運(yùn)行相應(yīng)的腳本,用戶將會收到一個(gè)郵件說明其中的原因。
轉(zhuǎn)載于:https://my.oschina.net/dclink/blog/194941
總結(jié)
以上是生活随笔為你收集整理的crontab环境变量的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 日均互动50万次 微信的营销的成功之道
- 下一篇: win8学习--------File