簡書不維護了遂黍,歡迎關(guān)注我的知乎:波羅學(xué)的個人主頁
此篇技術(shù)博文主要介紹的是crontab抹缕,Linux下的計劃任務(wù)管理工具伶氢。涉及內(nèi)容包括crontab使用配置趟径、常見坑的分析和編者總結(jié)的錯誤調(diào)試方法。
我的理解癣防,后臺任務(wù)通常分為兩種:常駐和定時蜗巧。之前的文章《pm2進程管理工具使用總結(jié)》主要針對的是常駐任務(wù)。今天來談?wù)刢rontab蕾盯,主要針對的是定時任務(wù)幕屹。
實驗環(huán)境:centos7
介紹crontab
crontab的服務(wù)進程名為crond,英文意為周期任務(wù)级遭。顧名思義望拖,crontab在Linux主要用于周期定時任務(wù)管理。通常安裝操作系統(tǒng)后挫鸽,默認已啟動crond服務(wù)说敏。crontab可理解為cron_table,表示cron的任務(wù)列表掠兄。類似crontab的工具還有at和anacrontab像云,但具體使用場景不同锌雀,可參見附錄《讓你學(xué)會Linux計劃任務(wù)》一文了解更多。
關(guān)于crontab的用途很多迅诬,如
- 定時系統(tǒng)檢測腋逆;
- 定時數(shù)據(jù)采集;
- 定時日志備份侈贷;
- 定時更新數(shù)據(jù)緩存惩歉;
- 定時生成報表;
...
等等任務(wù)
當(dāng)然俏蛮,更多使用場景是要以視具體情況而定了撑蚌。畢竟是工具通常都是常用規(guī)則總結(jié)而成的產(chǎn)物。
確認crond服務(wù)已經(jīng)安裝與開啟之后搏屑,下面開始具體說明
簡單示例
先來個簡單示例體驗一下争涌。
目標(biāo):每分鐘向/tmp/time.txt文件下寫入當(dāng)前時間
-
新建crontab任務(wù)
$ crontab -e // 打開crontab任務(wù)編輯 * * * * * date >> /tmp/time.txt
-
靜靜等待幾分鐘
$ cat /tmp/time.txt Do 29. Dez 22:45:01 CST 2016 Do 29. Dez 22:46:01 CST 2016 Do 29. Dez 22:47:01 CST 2016
從上面結(jié)果看出,每分鐘執(zhí)行了date并寫入到/tmp/time.txt辣恋。
簡單示例演示成功亮垫。下面從細節(jié)深入說明crontab使用。
使用選項
上面的實驗中使用了crontab命令的-e選項伟骨。我們來看看crontab命令中有哪些選項?
-e 選項 表示打開當(dāng)前用戶的crontab任務(wù)列表配置文件饮潦。當(dāng)然也可以直接打開,路徑通常是在/var/spool/cron/下携狭,文件以用戶名命名继蜡,如/var/spool/cron/root。不過逛腿,采用-e方式打開稀并,福利是可以幫助我們自動檢查任務(wù)配置符合規(guī)則。
-
-u 選項 指定某用戶的任務(wù)列表单默,很好理解稻轨。比如我當(dāng)前是root用戶,想操作poloxue用戶的任務(wù)列表雕凹。如下:
$ crontab -u poloxue -e
-l 選項 列出某用戶的所有任務(wù)列表
-r 選項 刪除某用戶的所有任務(wù)列表,這個選項使用小心為上政冻,估計也只是自己實驗時玩玩而已枚抵,正常不使用。
crontab命令的選項中明场,主要使用的就是以上幾個汽摹,理解比較簡單。
任務(wù)配置
說完了crontab的命令選項苦锨,下面開始真正的大戲逼泣,任務(wù)列表文件如何配置趴泌?
首先,看下crontab任務(wù)列表配置格式拉庶,示例文件如下:
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# 更多細節(jié) man 4 crontabs
# 計劃任務(wù)定義的例子:
# .---------------- 分 (0 - 59)
# | .------------- 時 (0 - 23)
# | | .---------- 日 (1 - 31)
# | | | .------- 月 (1 - 12)
# | | | | .---- 星期 (0 - 7) (星期日可為0或7)
# | | | | |
# * * * * * 執(zhí)行的命令
* * * * * date >> /time.txt 2>&1
從上面的示例文件可看出嗜憔,crontab的任務(wù)列表主要由兩部分組成:環(huán)境變量配置與定時任務(wù)配置∈险蹋可能大家在工作中更多是只用到了任務(wù)配置部分吉捶。
環(huán)境變量配置部分
理解環(huán)境變量配置這部分可以幫助我們減少去踩一些不必要的坑。簡單說明上面涉及的環(huán)境變量皆尔。
SHELL為/bin/bash呐舔,表示使用/bin/bash解釋執(zhí)行命令
PATH表示到哪些目錄路徑尋找命令程序,此環(huán)境變量的值說明了為什么我們在crontab中執(zhí)行命令時慷蠕,盡量要寫命令全路徑才能執(zhí)行的原因珊拼。
MAILTO變量作用是當(dāng)任務(wù)執(zhí)行有輸出時,內(nèi)容發(fā)送到哪個用戶的郵箱流炕。禁用可以設(shè)置MAILTO=""澎现。
當(dāng)我們在使用crontab時,發(fā)現(xiàn)某些定時任務(wù)不能順利執(zhí)行浪感,但shell控制臺執(zhí)行成功昔头,環(huán)境變量是否正確是我們需要首先關(guān)注的點之一。具體詳情可以看后面關(guān)于環(huán)境變量坑的說明影兽。
定時任務(wù)配置部分
這部分是crontab配置核心揭斧。
-
基本配置
如下所示配置共6列,前5列是關(guān)于執(zhí)行時間配置峻堰,最后1列是具體執(zhí)行命令讹开。.---------------- 分 (0 - 59) | .------------- 時 (0 - 23) | | .---------- 日 (1 - 31) | | | .------- 月 (1 - 12) | | | | .---- 星期 (0 - 6) (星期日可為0或7) | | | | | * * * * * 執(zhí)行的命令
第一列單位為分,表示每時第幾分鐘捐名,范圍為0-59旦万;
第二列單位為時,表示每天第幾小時镶蹋,范圍為0-23成艘;
第三列單位為日,表示每月第幾天贺归,范圍為1-31淆两;
第四列單位為月,表示每年第幾月拂酣,范圍為1-12秋冰;
第五列單位為星期,表示每星期第幾天婶熬,范圍0-7剑勾,0與7表示星期日埃撵,其他分別為星期1-6; -
時間配置段類型
根據(jù)時間列中值的不同設(shè)置方式虽另,編者總結(jié)出以下五種類型:固定某值暂刘,指定固定值,如指定1月1日0時0分執(zhí)行任務(wù)
0 0 1 1 * command
月日時分都指定了固定數(shù)值洲赵。
<font color=red>注:*在crontab中表示任意值都滿足條件鸳惯。</font>列表值,時間值是一個列表叠萍,如指定一個月內(nèi)2芝发、12、22日零時執(zhí)行任務(wù)
0 0 2,12,22 * * command
上述日指定多個值苛谷,2號辅鲸、12號和22號,以逗號分隔腹殿;
連續(xù)范圍值独悴,時間為連續(xù)范圍的值,如指定每個月1至7號零時執(zhí)行任務(wù)
0 0 1-7 * * command
上述日期為連續(xù)范圍的值1-7時
步長值锣尉,根據(jù)指定數(shù)值跳躍步長確定執(zhí)行時間刻炒,如指定凌晨1時開始每割3個小時0分執(zhí)行一次任務(wù)
0 1-24/3 * * * command
上述指定從凌晨1時每3個小時執(zhí)行任務(wù),如1點0分自沧,4點0分坟奥,7點0分等。
混合值拇厢,支持以上類型的組合爱谁,如指定每小時0至10分,22孝偎、33分以及0-60分鐘每隔20分鐘執(zhí)行任務(wù)访敌,如下
0-10,22,33,*/20 * * * * command
這里的分鐘值采取了多種類型組合指定,包括連續(xù)范圍值(0-7)衣盾,列表值(22,33)寺旺,步長值(*/20)。
<font color=red>聲明:這幾種時間配置類型是編者自己總結(jié),希望能幫助大家更好理解。有錯誤幫忙指出蝎宇。</font>
定時語句解析工具
通常在使用crontab添加任務(wù)時,我們會依靠自己已有知識編寫定時語句。當(dāng)需要測試語句是否正確時唉地,總需要一定時間等待證明其正確性据悔。作為一名牛逼的程序員传透,這種方式就太不酷了。有沒有一款工具极颓,只要我們給出語句朱盐,其就能告訴具體執(zhí)行時間呢?下面介紹一款老外開發(fā)的crontab在線解析工具菠隆。
工具地址:https://crontab.guru
下面是這個工具的截圖
從上面看出兵琳,我們輸入的語句解析結(jié)果為每天的04:05執(zhí)行任務(wù)。下面有這樣一行文字“next at 2016-12-31 04:05:00”骇径,告訴了我們最近一次的執(zhí)行時間躯肌。
<font color=red>注明:百度搜索“crontab在線解析”獲得的工具有坑,某些語句解析結(jié)果錯誤破衔。為避免大家受騙清女,這里提供具體地址:http://tool.lu/crontab/</font>
使用有坑
crontab使用中常會遇到各種坑。下面列出編者在使用中曾遇到的一些問題晰筛。
時間配置誤區(qū)
此處介紹兩種坑嫡丙,一種是由于基本功不足導(dǎo)致配置錯誤,而另一種則是多數(shù)人對crontab配置都存在的一個理解誤區(qū)读第。
-
整點時間設(shè)置錯誤
其實這個錯誤不用單獨說明曙博,但是編者剛開始接觸crontab時犯過,單獨拿出來說明一下怜瞒。如設(shè)定每天3點執(zhí)行一次某任務(wù)
下面列出錯誤方式父泳,當(dāng)我們聽到每天3點執(zhí)行一次某任務(wù)時,很多人會把重點放在3點盼砍,而忽略了執(zhí)行一次的需求尘吗。下面是個錯誤的例子
* 3 * * * command
這里會導(dǎo)致在三點的每分鐘都會執(zhí)行一次任務(wù),也就是執(zhí)行了60次浇坐。
正確方式如下睬捶,每天3點0時執(zhí)行任務(wù)0 3 * * * command
-
日與星期的關(guān)系誤區(qū)
這真的是個大誤區(qū),很多人都不知道的大誤區(qū)近刘。直接開始說明吧擒贸。好,首先做兩個練習(xí)
設(shè)置任務(wù)一:每月的1-7每天零時執(zhí)行某任務(wù)觉渴,答案如下:
0 0 1-7 * * date >> /tmp/date.txt
設(shè)置任務(wù)二:每星期的星期一零時執(zhí)行某任務(wù)介劫,答案如下:
0 0 * * 1 date >> /tmp/date.txt
上面兩個任務(wù)的設(shè)定都是正確的。
下面提出第三個任務(wù)案淋,設(shè)置每個月的第一個星期一零時執(zhí)行某任務(wù)
分解任務(wù)要求座韵,首先,第一個星期就是每個月的1-7日,而星期一就是星期一誉碴。所以我們理解的crontab任務(wù)配置如下
下面直接使用前面介紹的在線解析工具分析此語句宦棺,如下0 0 1-7 * 1 date >> /tmp/date.txt
解析結(jié)果顯示語句執(zhí)行時間為每月的1至7日和每星期一∏粒可以看到最近執(zhí)行時間是“next at 2017-01-01 00:00:00”代咸,這個時間也并非星期一。
這是crontab的一個特別容易誤解之處成黄,下面直接給出結(jié)論:
當(dāng)日和星期任一列包含時呐芥,日與星期兩者為并且的關(guān)系;
當(dāng)日和星期列中不包含時奋岁,日與星期兩者為或者的關(guān)系思瘟;
<font color=red>請注意,前面提到的那個百度搜索出來的工具分析結(jié)果顯示的確是每月第一個星期一厦取,這是錯誤的潮太。如有朋友持懷疑態(tài)度,可自行驗證虾攻,如有錯誤铡买,隨時告知。</font>
環(huán)境變量問題
當(dāng)我們剛使用crontab時霎箍,有人會告知所有命令盡量都使用絕對路徑奇钞,以防錯誤。為什么漂坏?這就和我們下面要談的環(huán)境變量有關(guān)了景埃。
-
首先,獲取控制臺環(huán)境變量看下
$ env XDG_SESSION_ID=10 HOSTNAME=localhost.localdomain SHELL=/bin/bash PERL_MB_OPT=--install_base /root/perl5 USER=root MAIL=/var/spool/mail/root PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/php5/bin PWD=/var/mail SHLVL=1 HOME=/root LOGNAME=root XDG_RUNTIME_DIR=/run/user/0 _=/usr/bin/env
<font color=red>考慮篇幅顶别,輸出有刪減谷徙。</font>
-
然后,獲取crontab環(huán)境變量信息
* * * * * /usr/bin/env > /tmp/env.txt
輸出結(jié)果驯绎,如下
$ cat /tmp/env.txt XDG_SESSION_ID=732 SHELL=/bin/sh USER=root PATH=/usr/bin:/bin PWD=/root LANG=de_DE.UTF-8 SHLVL=1 HOME=/root LOGNAME=root XDG_RUNTIME_DIR=/run/user/0 _=/usr/bin/en
對比分析兩者輸出
對比crontab與控制臺輸出完慧,我們發(fā)現(xiàn)兩者的環(huán)境變量差異很大。如果命令在控制臺執(zhí)行成功剩失,而在crontab執(zhí)行失敗屈尼,我們需要考慮是否命令涉及的環(huán)境變量在crontab和控制臺間存在差異。-
明白crontab使用絕對路徑執(zhí)行命令原因了嗎拴孤?
我們知道命令默認查找路徑是由PATH指定的脾歧。從上面輸出結(jié)果可知,控制臺的PATH值為
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/php/bin
crontab的PATH值為
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/php/bin
crontab的PATH值為
PATH=/usr/bin:/bin
/usr/local/php/bin/下面存在php命令演熟,在控制臺執(zhí)行成功
$ php index.php
因在crontab的PATH變量無/usr/local/php/bin/鞭执,其執(zhí)行php命令則會失敗。
-
解決方式
已知哪個環(huán)境變量導(dǎo)致問題,可以直接在crontab配置中加入變量配置兄纺。
不知哪個環(huán)境變量導(dǎo)致問題免猾,終極大招是引入控制臺環(huán)境變量,如下* * * * * source /$HOME/.bash_profile && command
當(dāng)然囤热,對于某特定環(huán)境變量或有特定的處理方式,如PATH获三,命令使用絕對路徑亦可解決旁蔼。
特殊符號%
%在crontab是特殊符號,具體含義如下:
-
第一個%表示標(biāo)準輸入的開始
* * * * * cat >> /tmp/cat.txt 2>&1 % stdin input
執(zhí)行成功之后疙教,查看/tmp/cat.txt
$ cat /tmp/cat.txt stdin input
我們看到標(biāo)準輸入寫入到了/tmp/cat.txt文件棺聊。
<font color=red>理解上面示例,首先需知cat >> /tmp/cat.txt 贞谓,作用是將標(biāo)準輸入重定向至/tmp/cat.txt限佩。</font>
-
其余%表示換行符
示例如下
* * * * * cat >> /tmp/cat_line.txt 2>&1 % stdin input 1 % stdin input 2 % stdin input 3
查看輸出
$ cat /tmp/cat_line.txt stdin input 1 stdin input 2 stdin input 3
有三行輸出
-
解決方式
既然是特殊字符,自然而然就想到了使用\進行轉(zhuǎn)義裸弦,如下:
* * * * * cat >> /tmp/cat_special.txt 2>&1 % per cent is \%. 2>&1
查看輸出
$ cat /tmp/cat_special.txt per cent is %.
執(zhí)行成功了祟同。自此,你就順利爬出了%特殊字符問題的坑理疙。
關(guān)于這個問題的具體說明晕城,可以參看附錄中的《Crontab and %》。
關(guān)于輸出重定向
當(dāng)我們不做輸出重定向時窖贤,如任務(wù)有大量輸出砖顷,或許有些無法解釋的問題。
-
輸出寫入郵件
crontab任務(wù)輸出默認寫入到執(zhí)行用戶的郵件中赃梧,如下演示:* * * * * date
命令輸出當(dāng)前日期滤蝠,下面查看當(dāng)前用戶的郵件
$ cat /var/spool/mail/$USER ... Sat Dec 31 17:45:01 CST 2016
由此可見,任務(wù)輸出的日期信息寫入到了用戶郵件中授嘀。
如任務(wù)有大量輸出物咳,會占用磁盤資源。但編者測試顯示粤攒,如磁盤容量不足所森,任務(wù)也會執(zhí)行,但輸出不會寫入郵件夯接;
-
關(guān)閉郵件功能
如何關(guān)閉焕济?設(shè)置MAILTO環(huán)境變量為空。如下MAILTO="" * * * * * date
是不是關(guān)閉郵件寫入就好了盔几?附錄《Linux中的crontab與sendmail》博文表明晴弃,關(guān)閉mail功能,輸出內(nèi)容將寫入到/var/spool/clientmqueue中,可能占滿分區(qū)的inode資源上鞠,導(dǎo)致任務(wù)無法執(zhí)行际邻。inode資源使用情況可通過如下命令獲取
$ df -i Filesystem Inodes IUsed IFree IUse% Mounted on /dev/sda1 512000 378 511622 1% /boot /dev/sda2 92672000 185351 92486649 1% /
抱歉!這種情況編者并未測出芍阎!但在公司的生產(chǎn)環(huán)境發(fā)現(xiàn)過未重定向則任務(wù)不執(zhí)行的情況世曾,加上后解決了問題。百度也搜索到了類似問題谴咸,如有朋友了解轮听,歡迎指教,萬分感謝岭佳。
當(dāng)然血巍,為了避免此類問題發(fā)生,建議任務(wù)都加上輸出重定向珊随,如下
* * * * * date >> /dev/null/ 2>&1
輸出到/dev/null中述寡,標(biāo)準輸入和標(biāo)準錯誤都應(yīng)處理。
如大家對重定向有疑惑叶洞,可參見附錄中的《Linux重定向》鲫凶,對文解釋不錯。
<font color=red>程序員的感悟:在技術(shù)的世界京办,當(dāng)我們不按常理做事掀序,事情也不會按常理犯錯。</font>
調(diào)試大招
最后的福利惭婿,編者根據(jù)自己的總結(jié)而梳理出一套快速定位crontab錯誤的思路不恭。兩個角度:
- 任務(wù)是否執(zhí)行
- 命令是否正確
任務(wù)是否執(zhí)行?
-
調(diào)試思路
首先财饥,通過日志確認任務(wù)是否執(zhí)行
然后换吧,如未執(zhí)行則分析定時語句,
最后钥星,定時沒有問題沾瓦,檢查crond服務(wù)是否開啟下面說明具體分析步驟。
-
日志確認
調(diào)試錯誤谦炒,日志通常是個利器贯莺,crontab也有日志。
編者的服務(wù)器中crontab日志文件位置為/var/log/cron查看日志
日志中包含任務(wù)執(zhí)行記錄宁改,配置錯誤提示缕探,任務(wù)配置編輯重載記錄,服務(wù)開啟等記錄还蹲。下面是日志的部分內(nèi)容爹耗,
$ vim /var/log/cron ... Dec 31 19:17:01 localhost crond[1455]: (CRON) bad day-of-week (/var/spool/cron/root) Dec 31 19:17:01 localhost CROND[4409]: (root) CMD (date) ...
這里截取了對調(diào)試比較重要的兩條記錄耙考,如下介紹
執(zhí)行記錄
Dec 31 19:17:01 localhost CROND[4409]: (root) CMD (date)
顯示12月21 19時17分1秒執(zhí)行了date命令
配置錯誤
Dec 31 19:17:01 localhost crond[1455]: (CRON) bad day-of-week (/var/spool/cron/root)
上面顯示/var/spool/cron/root的任務(wù)配置有錯,也就是root任務(wù)配置有錯潭兽。錯誤原因:bad day-of-week倦始,星期配置有錯。
語句是這樣的
* * * * date >> /dev/null 2>&1
明顯缺少了星期時間段山卦。
-
確認定時語句
通過上面的日志分析鞋邑,如任務(wù)沒有執(zhí)行,使用定時語句在線分析工具分析定時是否正確账蓉,非常簡單炫狱。
-
確認服務(wù)開啟
如果定時語句也正確,檢查服務(wù)是否開啟剔猿。檢測命令如下Systemd方式(centos7及以上)
$ systemctl status crond.service
SysVinit方式(centos7以下)
$ service crond status
查看命令輸出,如未開啟嬉荆,執(zhí)行如下命令開啟
Systemd方式(centos7及以上)
$ systemctl start crond.service
SysVinit方式(centos7以下)
$ service crond start
確認任務(wù)成功后归敬,如問題仍未解決,繼續(xù)往下看鄙早。
命令是否正確
確認命令成功與否汪茧,這里總結(jié)步驟大致如下
-
獲取命令執(zhí)行輸出
crontab中的命令執(zhí)行出錯,多數(shù)人都不知道如何調(diào)試限番。我們知道在控制臺執(zhí)行命令時舱污,可通過輸出獲取錯誤信息調(diào)試問題。這種方式在crontab同樣適用弥虐,方法就是利用重新向獲取輸出扩灯,進行分析。示例如下* * * * * php /root/index.php >> /tmp/debug.log 2>&1
這條任務(wù)總是執(zhí)行失敗霜瘪,我們把輸出重定向到/tmp/debug.log珠插。
查看debug.log,如下$ cat /tmp/debug.log /bin/sh: php: command not found /bin/sh: php: command not found
顯示php命令沒有找到颖对,很明顯的就可以確定是環(huán)境變量的問題捻撑。這種方式定位問題非常有效。
具體問題具體分析
有了命令執(zhí)行的輸出缤底,下面就是具體問題具體分析了顾患。或許是前面提到的各種坑个唧,也或許是命令本身所獨有的問題江解。
調(diào)試的方法到這里就說完了。但還是實踐為王坑鱼,需持續(xù)總結(jié)膘流,同時也希望大家不要在同樣的坑中重復(fù)犯錯絮缅。
crontab寫了這么長,希望能切實幫到大家呼股。有哪位朋友看到了最后嗎耕魄?表示佩服!
參考附錄
讓你學(xué)會Linux計劃任務(wù)
Linux中的crontab與sendmail
Crontab and %
Linux重定向