crontab 主要用於需要管理周期執行定時任務的場景,比如定期備份數據、定時殺毒、定期清理垃圾文件等。 Linux中的cron進程是一個主要的系統調度進程,可以在后台自動完成用戶指定的任務計划。它每分鍾檢查一遍各個用戶的”任務計划書“,也就是crontab文件,如果計划書中所指定的運行條件滿足,就立即為用戶執行計划書中的任務。那么,這個計划書放在哪兒 呢?就放在/var/spool/cron/crontabs目錄下面。
crontab 安裝
(有些系統默認已經帶了 crontab,無需安裝的朋友可以直接跳過本節)
安裝:
yum install -y vixie-cron
yum install -y crontabs
啟動:
systemctl start crond.service
重啟:
systemctl restart crond.service
設置開機啟動:
systemctl enable crondservice
命令格式
通常,系統並不允許用戶直接編輯計划書,/var/spool/cron/crontabs目錄也只有root用戶 才可讀寫。為了方便計划書的管理,系統提供了crontab命令:
crontab 主要有以下幾種命令格式
crontab [-u user] file crontab [-u user] [-l | -r | -e] [-i] [-s] crontab -n [ hostname ] crontab -c
命令參數:
- -u user:用來設定某個用戶的crontab服務,例如,"-u ixdba"表示設定ixdba用戶的crontab服務,此參數一般有root用戶來運行。
- -file:file是命令文件的名字,表示將file做為crontab的任務列表文件並載入crontab。如果在命令行中沒有指定這個文件,crontab命令將接受標准輸入(鍵盤)上鍵入的命令,並將它們載入crontab。
- -e:編輯某個用戶的crontab文件內容。如果不指定用戶,則表示編輯當前用戶的crontab文件。
- -l:顯示某個用戶的crontab文件內容,如果不指定用戶,則表示顯示當前用戶的crontab文件內容。
- -r:從/var/spool/cron目錄中刪除某個用戶的crontab文件,如果不指定用戶,則默認刪除當前用戶的crontab文件。
- -i:在刪除用戶的crontab文件時給確認提示。
crontab -e
這個命令用於編輯定時任務列表,當我們輸入完命令,按下回車鍵之后,它會使用默認編輯器(通常是vi/vim)打開一個文件,里面的內容可能是這樣子的:
這很可能是你看到的,在設置任何定時任務之前,這里是看不到任何內容的,如果你已經設置了內容的話,那么看到的可能是這樣的
這是我提前設置好的定時任務,我們暫時不解釋這個配置的功能,但從這里可以知道,通過 crontab -e
我們可以編輯定時任務。
如果我們什么都不做,直接退出編輯器會看到以下提示:
如果我們修改了這個文件,比如增加了一個任務
保存退出之后,我們可以看到成功的提示:
如果說,我們的配置有誤,那么系統就會提示我們, 重新編輯,你可以輸入 y
重新編輯 或者 n
放棄剛剛的配置的內容
crontab -l
這個命令可以列出當前的定時任務內容, 這與我們使用 crontab -e
看到的內容一樣,不同的是 crontab -e
可以編輯,而這里只能查看
crontab -r
這個命令用於刪除任務列表里面的內容(在刪除之前我們先做一個備份)
通過上面的示例可以看出,執行完 crontab -r
之后,我們的任務列表被清空了
crontab file
這個命令用於將保存在某個文件中的任務列表中的內容覆蓋到我們的任務列表中,我們剛剛在刪除任務列表前做了備份
現在來看一下,使用命令能否將任務列表還原回去
可以看到,通過 crontab file
命令,我們將剛剛備份的文件內容恢復到任務列表當中了。
有兩點需要注意:
- 這個命令的操作很粗暴,會用指定文件的內容直接覆蓋任務列表,使用前一定要想清楚,最好在操作前進行備份
- 用於覆蓋的文件內容必須是合法的內容,如果語法有誤,內容將不會更新,且會得到下圖所示的錯誤提示
crontab -ri
這個命令用於刪除任務列表里面的內容,但會在刪除之前讓你確認是否刪除
你可以輸入 y
確認刪除,也可以輸入 n
取消這次操作
crontab -u user_name
這里我們補充一點,Linux 中的每個用戶都可以有自己的定時任務,他們設置的任務被保存在 /var/spool/cron/
目錄下的同名文件中
這個命令跟 -i
一樣,需要與其它命令配合使用
crontab [-u user] file
crontab [-u user] [-l | -r | -e] [-i] [-s]
不使用 -u
時默認的就是當前用戶,如果你要配置其它用戶的任務列表
就可以使用這個命令
crontab -u user -e
當然,使用這個命令的前提是要有對應文件的操作權限,大多數情況下,這個命令都是 root 在用。
需要注意的是,根據文檔提示,如果你從一個普通用戶
su
到其它用戶,在進行crontab 命令時,就一定要加上-u
選項。但我實驗發現,su
到其它用戶之后,再進行 crontab 操作,默認使用的 su 之后的用戶。
注意:
1. crontab 文件名,提交了新計划文件之后,原來的計划是否還在呢?答案是否定的。這 種方法進行的是完全覆蓋,而非追加。同時要說明的是,當運行命令:crontab newplan.txt 之后,系統復制了一份newplan.txt的內容用來創建該用戶的計划書,存 放到/var/spool/cron/crontabs目錄下,newplan.txt與計划之間並無聯系。但建議將其 保留,作為計划書的副本。當要修改計划時,可先修改newplan.txt,然后再提交為新計划。
2.計划書的輸出和日志,如果用戶的計划書在運行時有輸出,用戶是無法直接從終端上看 到的。cron進程會將執行計划時產生的所有輸出數據和錯誤信息發送到指定用戶的郵箱 ,用戶可到郵箱中去查看,所以建議在計划中把有用的輸出數據重定向到文件中。要想 查看各個計划的執行情況,可以查看cron進程的日志文件:/var/log/cron。
3.更簡單的任務計划, 如果覺得這樣麻煩,還有一種簡單的方法。/etc下面有4個目錄: cron.hourly,cron.daily,cron.weekly,cron.weekly,這4個目錄下腳本的執行周期 分別是每小時,每天,每周,每月。根據自己的需要,將要運行的腳本直接放置到對應 的目錄下即可,系統會自動為你完成任務。
任務列表的語法
Crontab命令時間格式設置
* * * * * command 分 時 日 月 周 命令
使用 crontab -e
無需指定用戶名稱,因為這個命令就是使用用戶自己的身份來執行的。
補充: /etc/crontab 中的內容只能由 root 來設置,一般用於設置系統級的周期任務
從上面的圖里面可以知道,周期任務的配置語法由兩部分組成(使用 contab -e
時忽略 user-name)
- 時間規則
- 要執行命令或者腳本
時間規則
前面5個 * 分別代表 分、時、日、月、周
- 第一個 * 代表每一分鍾,也可以是 0-59 區間中的數字
- 第二個 * 代表每個小時,也可以是 0-23 區間中的數字
- 第三個 * 代表一個月中的每一天,也可以是 1-31 區間中的數字
- 第四個 * 代表一年中的每個月, 也可以是 1-13 區間中的數字,或者使用英文 jan,feb,mar,apr... 等來表示
- 第五個 * 代表一周中的每一天, 也可以是 0-6 區間中的數字(星期天使用 0 或者 7 表示),也可以使用 sum,mon,tue,wed,thu,fri,sat 來表示
除了上面的配置方式之外,crontab 還支持更靈活的配置方式:
*
代表取值范圍內的所有數字,如在分鍾單位,則表示每分鍾執行一次,其它時間點同理。第3段上的"*"代表[01-31]日,第4段上的"*"代表[01-12]月;,
用於列舉多個數字,如1,3,5
指定1,3,5這三個時間點;-
用於確定時間區間,如2-6
等價於2,3,4,5,6;
- /代表每的意思,*/5表示每5個單位,如在分鍾位置設置
*/2
表示每兩分鍾執行一次
注意,上述符號中的非標准符號不一定能在你的機器上正常運行,在使用前一定要先進行測試
命令
可以是shell命令或者執行某個已經寫好的腳本
實例
以下舉幾個實例的例子
表示每分鍾執行一次 * * * * * cmd 每個小時的0分和30分執行各執行一次 0,30 * * * * * cmd 每天的2點到5點每個小時的整點執行 0 2-5 * * * cmd 每年的 1月1日0點執行 0 0 1 1 * cmd 每天的12點到18點每隔3小時執行一次 0 12-18/3 * * * cmd 每個月最后的天的22點整執行(非標准語法,要先進行測試再投入生產環境) 0 22 L * * cmd 每晚的21:30重啟apache 30 21 * * * /usr/local/etc/rc.d/lighttpd restart 每月1、10、22日的4 : 45重啟apache 45 4 1,10,22 * * /usr/local/etc/rc.d/lighttpd restart 每周六、周日的1 : 10重啟apache 10 1 * * 6,0 /usr/local/etc/rc.d/lighttpd restart 每天18 : 00至23 : 00之間每隔30分鍾重啟apache 0,30 18-23 * * * /usr/local/etc/rc.d/lighttpd restart 每星期六的11 : 00 pm重啟apache 0 23 * * 6 /usr/local/etc/rc.d/lighttpd restart 每一小時重啟apache */1 * * * /usr/local/etc/rc.d/lighttpd restart 晚上11點到早上7點之間,每隔一小時重啟apache 23-7/1 * * * /usr/local/etc/rc.d/lighttpd restart 每月的4號與每周一到周三的11點重啟apache 0 11 4 * mon-wed /usr/local/etc/rc.d/lighttpd restart 一月一號的4點重啟apache 0 4 1 jan * /usr/local/etc/rc.d/lighttpd restart 每天早上7點執行一次 /bin/ls 0 7 * * * /bin/ls 在 12 月內, 每天的早上 6 點到 12 點中,每隔3個小時執行一次 /usr/bin/backup 0 6-12/3 * 12 * /usr/bin/backup 周一到周五每天下午 5:00 寄一封信給 alex@domain.name 0 17 * * 1-5 mail -s "hi" alex@domain.name < /tmp/maildata 每月每天的午夜 0 點 20 分, 2 點 20 分, 4 點 20 分....執行 echo "haha" 20 0-23/2 * * * echo "haha"
每個星期一凌晨執行
0 0 * * 1 echo Monday >> /home/test.txt
cron.allow 與 cron.deny
執行cron任務的權限是可以通過 /etc/cron.allow
和 /etc/cron.deny
兩個文件進行配置。
- cron.allow 用於配置哪些用戶可以使用 crontab
- cron.deny 用於配置哪些用戶禁止使用 crontab
這兩個文件的內容為每一行一個用戶名,或者為空
- 如果 cron.allow 文件存在的話,需要限權的用戶名必須在這個文件里面
- 如果 cron.deny 文件存在的話,需要權限的用戶不能出現在這個文件里面
- 如果兩個文件都不存在的話,則只有 root 有權限使用 crontab
如果兩個文件都存在,/etc/cron.allow優先。當上述兩個文件都不存在時,一個普通使用執行 crontab 命令會得到以下錯誤
環境變量
cron進程執行任務時,並不加載計划書所屬用戶的環境變量,只加載幾個最基本的環境變量,比如執行任務的sh,$HOME,$MAILTO等。這幾個環境變量的定義是在 /etc/crontab文件中。其中$MAILTO是指定計划執行過程中發生錯誤或者有數據輸出時發送郵件到哪個用戶。
在實際使用過程中, 我們都會編輯好一個.sh
文件,設置好權限(一般是增加執行權限 chmod +x task.sh
)。測試成功之后,興高采烈地把它添加到 crontab 的任務列表里面,結果遲遲沒有得到預期結果。我之前碰到這樣的情況,直接執行腳本沒問題,但使用 crontab 執行卻報錯,查看日志發現是環境變量的問題。
解決的辦法很簡單,只要在腳本內提前導入環境變量即可:
執行結果保存
如果crontab不重定向輸出,並且crontab所執行的命令有輸出內容的話,是一件非常危險的事情。因為該輸出內容會以郵件的形式發送給用戶,內容存儲在郵件文件
/var/spool/mail/$user
如果命令執行比較頻繁(如每分鍾一次),或者命令輸出內容較多,會使這個郵件文件不斷追加內容,文件越來越大。而郵件文件一般存放在根分區,根分區一般相對較小,所以會造成根分區寫滿而無法登錄服務器。
可以在配置任務的時候,在最后加入以下將執行過程中輸出的內容保存到自己想要的地方。
*/5 * * * * cmd > /var/log/cron_task.log 2>&1 &
名詞解釋
在shell中,每個進程都和三個系統文件相關聯:標准輸入stdin,標准輸出stdout和標准錯誤stderr,三個系統文件的文件描述符分別為0,1和2。所以這里2>&1的意思就是將標准錯誤也輸出到標准輸出當中。
> 就相當於 1> 也就是重定向標准輸出,不包括標准錯誤。通過2>&1,就將標准錯誤重定向到標准輸出了(stderr已作為stdout的副本),那么再使用>重定向就會將標准輸出和標准錯誤信息一同重定向了。如果只想重定向標准錯誤到文件中,則可以使用2> file。
不輸出內容 */5 * * * * /root/XXXX.sh &>/dev/null 2>&1 將正確和錯誤日志都輸出到 /tmp/load.log */1 * * * * /root/XXXX.sh > /tmp/load.log 2>&1 & 只輸出正確日志到 /tmp/load.log */1 * * * * /root/XXXX.sh > /tmp/load.log & 等同於 */1 * * * * /root/XXXX.sh 1>/tmp/load.log & 只輸出錯誤日志到 /tmp/load.log */1 * * * * /root/XXXX.sh 2> /tmp/load.log &
日志文件
我們可以查看 /var/log/cron
文件的內容來查看服務器執行了哪些任務
(我的是CentOS, 如果是Ubuntu可以到/var/log/cron.log
查看)
待補充
以下幾點是我看了文檔之后還不太明白的幾點(主要還是英文水平還不夠。。)
- crontab [-u user] -s
- crontab -n [hostname]
- crontab -c
- /etc/crontab 和 /etc/cron.d 文件內也可以設置任務列表,具體的使用場景我還沒有接觸過
以上所有內容是結合自己的實踐與官方文檔加上網友們的文章寫成,還有很多自己不理解的,希望看到的朋友如果有知道的也評論告訴我哦,謝謝啦
ReadMore
man cron
man crontab
- crontab校驗工具及語法介紹
- crontab 腳本錯誤日志和正確的輸出寫入到文件
參考: