【BASH】回顧與知識點梳理 二十八
- 二十八. 例行性工作排程(crontab)
- 28.1 什么是例行性工作排程
- Linux 工作排程的種類: at, cron
- CentOS Linux 系統上常見的例行性工作
- 28.2 僅執行一次的工作排程
- atd 的啟動
- at 的運作方式
- 實際運作單一工作排程
- at 工作的管理
- batch:系統有空時才進行背景任務
- 28.3 循環執行的例行性工作排程
- 使用者的設定
- 28.4 系統的配置文件: /etc/crontab, /etc/cron.d/*
- crond 服務讀取配置文件的位置
- 一些注意事項
- 資源分配不均的問題
- 取消不要的輸出項目
- 安全的檢驗
- 周與日月不可同時并存
- 28.5 可喚醒停機期間的工作任務
- 什么是 anacron
- anacron 與 /etc/anacrontab
該系列目錄 --> 【BASH】回顧與知識點梳理(目錄)
二十八. 例行性工作排程(crontab)
學習了基礎篇也一陣子了,你會發現到為什么系統常常會主動的進行一些任務?這些任務到底是誰在設定工作的? 如果你想要讓自己設計的備份程序可以自動的在系統底下執行,而不需要手動來啟動他,又該如何處置? 這些例行的工作可能又分為『單一』工作與『循環』工作,在系統內又是哪些服務在負責? 還有還有,如果你想要每年在老婆的生日前一天就發出一封信件提醒自己不要忘記,可以辦的到嗎? 嘿嘿!這些種種要如何處理,就看看這一章先!
28.1 什么是例行性工作排程
那么 Linux 的例行性工作是如何進行排程的呢?所謂的排程就是將這些工作安排執行的流程之意
!咱們的 Linux 排程就是透過 crontab 與 at 這兩個東西!這兩個玩意兒有啥異同?就讓我們來瞧瞧先!
Linux 工作排程的種類: at, cron
從上面的說明當中,我們可以很清楚的發現兩種工作排程的方式:
- 一種是例行性的,就是每隔一定的周期要來辦的事項;
- 一種是突發性的,就是這次做完以后就沒有的那一種
那么在 Linux 底下如何達到這兩個功能呢?那就得使用 at 與 crontab 這兩個好東西啰!
- at :at 是個可以處理僅執行一次就結束排程的指令,不過要執行 at 時, 必須要有 atd 這個服務的支援才行。在某些新版的 distributions 中,atd 可能預設并沒有啟動,那么 at 這個指令就會失效呢!不過我們的 CentOS 預設是啟動的!
- crontab :crontab 這個指令所設定的工作將會循環的一直進行下去! 可循環的時間為分鐘、小時、每周、每月或每年等。crontab 除了可以使用指令執行外,亦可編輯 /etc/crontab 來支持。 至于讓 crontab 可以生效的服務則是 crond 這個服務喔!
CentOS Linux 系統上常見的例行性工作
如果你曾經使用過 Linux 一陣子了,那么你大概會發現到 Linux 會主動的幫我們進行一些工作呢!比方說自動的進行在線更新 (on-line update)、自動的進行 updatedb更新文件名數據庫、自動的作登錄檔分析 (所以 root 常常會收到標題為 logwatch 的信件) 等等。這是由于系統要正常運作的話, 某些在背景底下的工作必須要定時進行的緣故。基本上 Linux 系統常見的例行性任務有:
- 進行登錄檔的輪替 (log rotate)
Linux 會主動的將系統所發生的各種信息都記錄下來,這就是登錄檔。由于系統會一直記錄登錄信息,所以登錄文件將會越來越大!我們知道大型文件不但占容量還會造成讀寫效能的困擾, 因此適時的將登錄文件數據挪一挪,讓舊的數據與新的數據分別存放,則比較可以有效的記錄登錄信息。這就是log rotate
的任務!這也是系統必要的例行任務; - 登錄文件分析 logwatch 的任務:
如果系統發生了軟件問題、硬件錯誤、資安問題等,絕大部分的錯誤信息都會被記錄到登錄文件中, 因此系統管理員的重要任務之一就是分析登錄檔。但你不可能手動透過 vim 等軟件去檢視登錄文件,因為數據太復雜了! 我們的 CentOS 提供了一只程序『 logwatch 』來主動分析登錄信息,所以你會發現,你的 root 老是會收到標題為 logwatch 的信件,那是正常的!你最好也能夠看看該信件的內容喔! - 建立 locate 的數據庫:
在前文我們談到的 locate 指令時, 我們知道該指令是透過已經存在的文件名數據庫來進行系統上文件名的查詢。我們的文件名數據庫是放置到/var/lib/mlocate/
中。 問題是,這個數據庫怎么會自動更新啊?嘿嘿!這就是系統的例行性工作所產生的效果啦!系統會主動的進行updatedb
喔! - man page 查詢數據庫的建立:
與 locate 數據庫類似的,可提供快速查詢的man page db
也是個數據庫,但如果要使用 man page 數據庫時,就得要執行 mandb 才能夠建立好啊! 而這個 man page 數據庫也是透過系統的例行性工作排程來自動執行的哩! - RPM 軟件登錄文件的建立:
RPM 是一種軟件管理的機制。由于系統可能會常常變更軟件, 包括軟件的新安裝、非經常性更新等,都會造成軟件文件名的差異。為了方便未來追蹤,系統也幫我們將文件名作個排序的記錄呢! 有時候系統也會透過排程來幫忙 RPM 數據庫的重新建置喔! - 移除暫存檔:
某些軟件在運作中會產生一些暫存檔,但是當這個軟件關閉時,這些暫存盤可能并不會主動的被移除。 有些暫存盤則有時間性,如果超過一段時間后,這個暫存盤就沒有效用了,此時移除這些暫存盤就是一件重要的工作! 否則磁盤容量會被耗光。系統透過例行性工作排程執行名為tmpwatch
的指令來刪除這些暫存檔呢! - 與網絡服務有關的分析行為:
如果你有安裝類似 WWW 服務器軟件 (一個名為 apache 的軟件),那么你的 Linux 系統通常就會主動的分析該軟件的登錄文件。 同時某些憑證與認證的網絡信息是否過期的問題,我們的 Linux 系統也會很親和的幫你進行自動檢查!
28.2 僅執行一次的工作排程
首先,我們先來談談單一工作排程的運作,那就是 at 這個指令的運作!
atd 的啟動
要使用單一工作排程時,我們的 Linux 系統上面必須要有負責這個排程的服務,那就是 atd 這個玩意兒。 不過并非所有的 Linux distributions 都預設會把他打開的,所以呢,某些時刻我們必須要手動將他啟用才行。 啟用的方法很簡單,就是這樣:
[root@study ~]# systemctl restart atd # 重新啟動 atd 這個服務
[root@study ~]# systemctl enable atd # 讓這個服務開機就自動啟動
[root@study ~]# systemctl status atd # 查閱一下 atd 目前的狀態
at 的運作方式
我們使用 at 這個指令來產生所要運作的工作,并將這個工作以文本文件的方式寫入 /var/spool/at/ 目錄內,該工作便能等待 atd 這個服務的取用與執行了
。就這么簡單。
不過,并不是所有的人都可以進行 at 工作排程喔!為什么?因為安全的理由啊~ 很多主機被所謂的『綁架』后,最常發現的就是他們的系統當中多了很多的怪客程序 (cracker program), 這些程序非常可能運用工作排程來執行或搜集系統信息,并定時的回報給怪客團體! 所以啰,除非是你認可的賬號,否則先不要讓他們使用 at 吧!那怎么達到使用 at 的列管呢?
我們可以利用 /etc/at.allow 與 /etc/at.deny 這兩個文件來進行 at 的使用限制呢! 加上這兩個文件后,at 的工作情況其實是這樣的:
- 先找尋
/etc/at.allow
這個文件,寫在這個文件中的使用者才能使用 at ,沒有在這個文件中的使用者則不能使用 at (即使沒有寫在 at.deny 當中
); - 如果
/etc/at.allow
不存在,就尋找/etc/at.deny
這個文件,若寫在這個 at.deny 的使用者則不能使用 at
,而沒有在這個 at.deny 文件中的使用者,就可以使用 at 咯; - 如果兩個文件都不存在,那么只有 root 可以使用 at 這個指令。
透過這個說明,我們知道 /etc/at.allow 是管理較為嚴格的方式,而 /etc/at.deny 則較為松散 (因為賬號沒有在該文件中,就能夠執行 at 了)。在一般的 distributions 當中,由于假設系統上的所有用戶都是可信任的, 因此系統通常會保留一個空的 /etc/at.deny 文件,意思是允許所有人使用 at 指令的意思 (您可以自行檢查一下該文件)。 不過,萬一你不希望有某些使用者使用 at 的話,將那個使用者的賬號寫入 /etc/at.deny 即可! 一個賬號寫一行。
實際運作單一工作排程
單一工作排程的進行就使用 at 這個指令啰!這個指令的運作非常簡單!將 at 加上一個時間即可!基本的語法如下:
[root@study ~]# at [-mldv] TIME
[root@study ~]# at -c 工作號碼
選項與參數:
-m :當 at 的工作完成后,即使沒有輸出訊息,亦以 email 通知使用者該工作已完成。
-l :at -l 相當于 atq,列出目前系統上面的所有該用戶的 at 排程;
-d :at -d 相當于 atrm ,可以取消一個在 at 排程中的工作;
-v :可以使用較明顯的時間格式欄出 at 排程中的任務欄表;
-c :可以列出后面接的該項工作的實際指令內容。TIME:時間格式,這里可以定義出『什么時候要進行 at 這項工作』的時間,格式有:HH:MM ex> 04:00在今日的 HH:MM 時刻進行,若該時刻已超過,則明天的 HH:MM 進行此工作。HH:MM YYYY-MM-DD ex> 04:00 2015-07-30強制規定在某年某月的某一天的特殊時刻進行該工作!HH:MM[am|pm] [Month] [Date] ex> 04pm July 30也是一樣,強制在某年某月某日的某時刻進行!HH:MM[am|pm] + number [minutes|hours|days|weeks]ex> now + 5 minutes ex> 04pm + 3 days就是說,在某個時間點『再加幾個時間后』才進行。
# 范例一:再過五分鐘后,將 /root/.bashrc 寄給 root 自己
[root@study ~]# at now + 5 minutes <==記得單位要加 s 喔!
at> /bin/mail -s "testing at job" root < /root/.bashrc
at> <EOT> <==這里輸入 [ctrl] + d 就會出現 <EOF> 的字樣!代表結束!
job 2 at Thu Jul 30 19:35:00 2015
# 上面這行信息在說明,第 2 個 at 工作將在 2015/07/30 的 19:35 進行!
# 而執行 at 會進入所謂的 at shell 環境,讓你下達多重指令等待運作!# 范例二:將上述的第 2 項工作內容列出來查閱
[root@study ~]# at -c 2
#!/bin/sh <==就是透過 bash shell 的啦!
# atrun uid=0 gid=0
# mail root 0
umask 22
....(中間省略許多的環境變量項目)....
cd /etc/cron\.d || {echo 'Execution directory inaccessible' >&2exit 1
}
${SHELL:-/bin/sh} << 'marcinDELIMITER410efc26'
/bin/mail -s "testing at job" root < /root/.bashrc # 這一行最重要!
marcinDELIMITER410efc26
# 你可以看到指令執行的目錄 (/root),還有多個環境變量與實際的指令內容啦!# 范例三:由于機房預計于 2015/08/05 停電,我想要在 2015/08/04 23:00 關機?
[root@study ~]# at 23:00 2015-08-04
at> /bin/sync
at> /bin/sync
at> /sbin/shutdown -h now
at> <EOT>
job 3 at Tue Aug 4 23:00:00 2015
# 您瞧瞧! at 還可以在一個工作內輸入多個指令呢!不錯吧!
事實上,當我們使用 at 時會進入一個 at shell 的環境來讓用戶下達工作指令,此時,建議你最好使用絕對路徑來下達你的指令,比較不會有問題喔
!由于指令的下達與 PATH 變量有關, 同時與當時的工作目錄也有關連 (如果有牽涉到文件的話),因此使用絕對路徑來下達指令,會是比較一勞永逸的方法。為什么呢?舉例來說,你在 /tmp 下達『 at now 』然后輸入『 mail -s “test” root < .bashrc 』,問一下,那個 .bashrc 的文件會是在哪里?答案是『 /tmp/.bashrc 』!因為 at 在運作時,會跑到當時下達 at 指令的那個工作目錄的緣故啊
!
有些朋友會希望『我要在某某時刻,在我的終端機顯示出 Hello 的字樣
』,然后就在 at 里面下達這樣的信息『 echo “Hello” 』。等到時間到了,卻發現沒有任何訊息在屏幕上顯示,這是啥原因啊?這是因為 at 的執行與終端機環境無關,而所有 standard output/standard error output 都會傳送到執行者的 mailbox 去啦!所以在終端機當然看不到任何信息。那怎辦?沒關系, 可以透過終端機的裝置來處理!假如你在 tty1 登入,則可以使用『 echo "Hello" > /dev/tty1
』來取代。
要注意的是,如果在 at shell 內的指令并沒有任何的訊息輸出,那么 at 默認不會發email 給執行者的。 如果你想要讓 at 無論如何都發一封 email 告知你是否執行了指令,那么可以使用『 at -m 時間格式 』來下達指令喔! at 就會傳送一個訊息給執行者,而不論該指令執行有無訊息輸出了!
at 有另外一個很棒的優點,那就是『背景執行(后臺執行)
』的功能了!
- 脫機繼續工作的任務:鳥哥初次接觸 Unix 為的是要跑空氣質量模式, 那是一種大型的程序,這個程序在當時的硬件底下跑,一個案例要跑 3 天!由于鳥哥也要進行其他研究工作,因此常常使用 Windows 98 (你沒看錯!鳥哥是老人…) 來聯機到 Unix 工作站跑那個 3 天的案例!結果你也該知道, Windows 98 連開三天而不當機的機率是很低的~@_@~ 而當機時,所有在 Windows 上的聯機都會中斷!包括鳥哥在跑的那個程序也中斷了~嗚嗚~明明再三個鐘頭就跑完的程序, 由于當機害我又得跑 3 天!
- 另一個常用的時刻則是例如上面的范例三,由于某個突發狀況導致你必須要進行某項工作時,這個 at 就很好用啦!
由于 at 工作排程的使用上,系統會將該項 at 工作獨立出你的 bash 環境中, 直接交給系統的 atd 程序來接管,因此,當你下達了 at 的工作之后就可以立刻脫機了, 剩下的工作就完全交給 Linux 管理即可
!所以啰,如果有長時間的網絡工作時,嘿嘿! 使用 at 可以讓你免除網絡斷線后的困擾喔!^_^
at 工作的管理
那么萬一我下達了 at 之后,才發現指令輸入錯誤,該如何是好?就將他移除啊!利用 atq 與 atrm 吧!
[root@study ~]# atq #查詢
[root@study ~]# atrm (jobnumber) #移除# 范例一:查詢目前主機上面有多少的 at 工作排程?
[root@study ~]# atq
3 Tue Aug 4 23:00:00 2015 a root
# 上面說的是:『在 2015/08/04 的 23:00 有一項工作,該項工作指令下達者為
# root』而且,該項工作的工作號碼 (jobnumber) 為 3 號喔!# 范例二:將上述的第 3 個工作移除!
[root@study ~]# atrm 3
[root@study ~]# atq
# 沒有任何信息,表示該工作被移除了!
如此一來,你可以利用 atq 來查詢,利用 atrm 來刪除錯誤的指令,利用 at 來直接下達單一工作排程!很簡單吧! 不過,有個問題需要處理一下。如果你是在一個非常忙碌的系統下運作 at , 能不能指定你的工作在系統較閑的時候才進行呢
?可以的,那就使用 batch 指令吧!
batch:系統有空時才進行背景任務
其實 batch 是利用 at 來進行指令的下達啦!只是加入一些控制參數而已。這個 batch 神奇的地方在于:他會在 CPU 的工作負載小于 0.8 的時候,才進行你所下達的工作任務啦! 那什么是工作負載0.8 呢?這個工作負載的意思是: CPU 在單一時間點所負責的工作數量。不是 CPU 的使用率喔!舉例來說,如果我有一只程序他需要一直使用 CPU 的運算功能,那么此時 CPU 的使用率可能到達100% , 但是 CPU 的工作負載則是趨近于『 1 』,因為 CPU 僅負責一個工作嘛!如果同時執行這樣的程序兩支呢? CPU 的使用率還是 100% ,但是工作負載則變成 2 了!了解乎?
所以也就是說,當 CPU 的工作負載越大,代表 CPU 必須要在不同的工作之間進行頻繁的工作切換。這樣的 CPU 運作情況我們在第零章有談過,忘記的話請回去瞧瞧!因為一直切換工作,所以會導致系統忙碌啊! 系統如果很忙碌,還要額外進行 at ,不太合理!所以才有 batch 指令的產生!
在 CentOS 7 底下的 batch 已經不再支持時間參數了,因此 batch 可以拿來作為判斷是否要立刻執行背景程序的依據! 我們底下來實驗一下 batch 好了!為了產生 CPU 較高的工作負載,因此我們用了 12 章里面計算 pi 的腳本,連續執行 4 次這只程序, 來仿真高負載,然后來玩一玩 batch 的工作現象:
# 范例一:請執行 pi 的計算,然后在系統閑置時,執行 updatdb 的任務
[root@study ~]# echo "scale=100000; 4*a(1)" | bc -lq &
[root@study ~]# echo "scale=100000; 4*a(1)" | bc -lq &
[root@study ~]# echo "scale=100000; 4*a(1)" | bc -lq &
[root@study ~]# echo "scale=100000; 4*a(1)" | bc -lq &
# 然后等待個大約數十秒的時間,之后再來確認一下工作負載的情況!
[root@study ~]# uptime
19:56:45 up 2 days, 19:54, 2 users, load average: 3.93, 2.23, 0.96
[root@study ~]# batch
at> /usr/bin/updatedb
at> <EOT>
job 4 at Thu Jul 30 19:57:00 2015
[root@study ~]# date;atq
Thu Jul 30 19:57:47 CST 2015
4 Thu Jul 30 19:57:00 2015 b root
# 可以看得到,明明時間已經超過了,卻沒有實際執行 at 的任務!
[root@study ~]# jobs
[1] Running echo "scale=100000; 4*a(1)" | bc -lq &
[2] Running echo "scale=100000; 4*a(1)" | bc -lq &
[3]- Running echo "scale=100000; 4*a(1)" | bc -lq &
[4]+ Running echo "scale=100000; 4*a(1)" | bc -lq &
[root@study ~]# kill -9 %1 %2 %3 %4
# 這時先用 jobs 找出背景工作,再使用 kill 刪除掉四個背景工作后,慢慢等待工作負載的下降
[root@study ~]# uptime; atq
20:01:33 up 2 days, 19:59, 2 users, load average: 0.89, 2.29, 1.40
4 Thu Jul 30 19:57:00 2015 b root
[root@study ~]# uptime; atq
20:02:52 up 2 days, 20:01, 2 users, load average: 0.23, 1.75, 1.28
# 在 19:59 時,由于 loading 還是高于 0.8,因此 atq 可以看得到 at job 還是持續再等待當中喔!
# 但是到了 20:01 時, loading 降低到 0.8 以下了,所以 atq 就執行完畢啰!
使用 uptime 可以觀察到 1, 5, 15 分鐘的『平均工作負載』量,因為是平均值,所以當我們如上表刪除掉四個工作后,工作負載不會立即降低, 需要一小段時間讓這個 1 分鐘平均值慢慢回復到接近 0 啊!當小于 0.8 之后的『整分鐘時間』時,atd 就會將 batch 的工作執行掉了!
什么是『整分鐘時間
』呢?不論是 at 還是底下要介紹的 crontab,他們最小的時間單位是『分鐘』,所以,基本上,他們的工作是『每分鐘檢查一次
』來處理的! 就是整分 (秒為 0 的時候
),這樣了解乎?同時,你會發現其實 batch 也是使用 atq/atrm 來管理的!
28.3 循環執行的例行性工作排程
相對于 at 是僅執行一次的工作,循環執行的例行性工作排程則是由 cron (crond) 這個系統服務來控制的。剛剛談過 Linux 系統上面原本就有非常多的例行性工作,因此這個系統服務是默認啟動的。另外, 由于使用者自己也可以進行例行性工作排程,所以啰, Linux 也提供使用者控制例行性工作排程的指令 (crontab)。 底下我們分別來聊一聊啰!
使用者的設定
使用者想要建立循環型工作排程時,使用的是 crontab 這個指令啦~不過,為了安全性的問題,與 at 同樣的,我們可以限制使用 crontab 的使用者賬號喔!使用的限制數據有:
- /etc/cron.allow:
將可以使用 crontab 的賬號寫入其中,若不在這個文件內的使用者則不可使用 crontab; - /etc/cron.deny:
將不可以使用 crontab 的賬號寫入其中,若未記錄到這個文件當中的使用者,就可以使用 crontab 。
與 at 很像吧!同樣的,以優先級來說, /etc/cron.allow 比 /etc/cron.deny 要優先, 而判斷上面,這兩個文件只選擇一個來限制而已,因此,建議你只要保留一個即可, 免得影響自己在設定上面的判斷!一般來說,系統默認是保留 /etc/cron.deny , 你可以將不想讓他執行 crontab 的那個使用者寫入 /etc/cron.deny 當中,一個賬號一行!
當用戶使用 crontab 這個指令來建立工作排程之后,該項工作就會被紀錄到 /var/spool/cron/ 里面去了,而且是以賬號來作為判別的喔
!舉例來說, dmtsai 使用 crontab 后, 他的工作會被紀錄到/var/spool/cron/dmtsai 里頭去!但請注意,不要使用 vi 直接編輯該文件, 因為可能由于輸入語法錯誤,會導致無法執行 cron 喔
!另外, cron 執行的每一項工作都會被紀錄到 /var/log/cron 這個登錄檔
中,所以啰,如果你的 Linux 不知道有否被植入木馬時,也可以搜尋一下 /var/log/cron 這個登錄檔呢!
好了,那么我們就來聊一聊 crontab 的語法吧!
[root@study ~]# crontab [-u username] [-l|-e|-r]
選項與參數:
-u :只有 root 才能進行這個任務,亦即幫其他使用者建立/移除 crontab 工作排程;
-e :編輯 crontab 的工作內容
-l :查閱 crontab 的工作內容
-r :移除所有的 crontab 的工作內容,若僅要移除一項,請用 -e 去編輯。
# 范例一:用 dmtsai 的身份在每天的 12:00 發信給自己
[dmtsai@study ~]$ crontab -e
# 此時會進入 vi 的編輯畫面讓您編輯工作!注意到,每項工作都是一行。0 12 * * * mail -s "at 12:00" dmtsai < /home/dmtsai/.bashrc
#分 時 日 月 周 |<==============指令串========================>|
預設情況下,任何使用者只要不被列入 /etc/cron.deny 當中,那么他就可以直接下達『 crontab -e
』去編輯自己的例行性命令了!整個過程就如同上面提到的,會進入 vi 的編輯畫面, 然后以一個工作一行來編輯,編輯完畢之后輸入『 :wq 』儲存后離開 vi 就可以了! 而每項工作 (每行) 的格式都是具有六個字段,這六個字段的意義為:
代表意義 | 分鐘 | 小時 | 日期 | 月份 | 周 | 指令 |
---|---|---|---|---|---|---|
數字范圍 | 0-59 | 0-23 | 1-31 | 1-12 | 0-7 | 呀就指令啊 |
比較有趣的是那個『周
』喔!周的數字為 0 或 7 時
,都代表『星期天
』的意思!另外,還有一些輔助的字符,大概有底下這些:
特殊字符 | 代表意義 |
---|---|
* (星號) | 代表任何時刻都接受的意思!舉例來說,范例一內那個日、月、周都是 * , 就代表著『不論何月、何日的禮拜幾的 12:00 都執行后續指令』的意思! |
, (逗號) | 代表分隔時段的意思。舉例來說,如果要下達的工作是 3:00 與 6:00 時,就會是: 0 3,6 * * * command 時間參數還是有五欄,不過第二欄是 3,6 ,代表 3 與 6 都適用! |
- (減號) | 代表一段時間范圍內,舉例來說, 8 點到 12 點之間的每小時的 20 分都進行一項工作: 20 8-12 * * * command 仔細看到第二欄變成 8-12 喔!代表 8,9,10,11,12 都適用的意思! |
/n (斜線) | 那個 n 代表數字,亦即是『每隔 n 單位間隔』的意思,例如每五分鐘進行一次,則: */5 * * * * command 很簡單吧!用 * 與 /5 來搭配,也可以寫成 0-59/5 ,相同意思! |
我們就來搭配幾個例子練習看看吧!底下的案例請實際用 dmtsai 這個身份作看看喔!后續的動作才能夠搭配起來!
假若你的女朋友生日是 5 月 2 日,你想要在 5 月 1 日的 23:59 發一封信給他,這封信的內容已經寫在/home/dmtsai/lover.txt 內了,該如何進行?
答:直接下達crontab -e
之后,編輯成為:59 23 1 5 * mail kiki < /home/dmtsai/lover.txt
那樣的話,每年 kiki 都會收到你的這封信喔!(當然啰,信的內容就要每年變一變啦!假如每五分鐘需要執行 /home/dmtsai/test.sh 一次,又該如何?
答:同樣使用 crontab -e 進入編輯:*/5 * * * * /home/dmtsai/test.sh
那個 crontab 每個人都只有一個文件存在,就是在 /var/spool/cron
里面啊! 還有建議您:『指令下達時,最好使用絕對路徑,這樣比較不會找不到執行檔喔!』
假如你每星期六都與朋友有約,那么想要每個星期五下午 4:30 告訴你朋友星期六的約會不要忘記,則:
答:還是使用 crontab -e 啊!30 16 * * 5 mail friend@his.server.name < /home/dmtsai/friend.txt
該如何查詢使用者目前的 crontab 內容呢?我們可以這樣來看看:
[dmtsai@study ~]$ crontab -l
0 12 * * * mail -s "at 12:00" dmtsai < /home/dmtsai/.bashrc
59 23 1 5 * mail kiki < /home/dmtsai/lover.txt
*/5 * * * * /home/dmtsai/test.sh
30 16 * * 5 mail friend@his.server.name < /home/dmtsai/friend.txt
# 注意,若僅想要移除一項工作而已的話,必須要用 crontab -e 去編輯~
# 如果想要全部的工作都移除,才使用 crontab -r 喔!
[dmtsai@study ~]$ crontab -r
[dmtsai@study ~]$ crontab -l
no crontab for dmtsai
28.4 系統的配置文件: /etc/crontab, /etc/cron.d/*
這個『 crontab -e 』是針對使用者的 cron 來設計的,如果是『系統的例行性任務
』時, 該怎么辦呢?是否還是需要以 crontab -e 來管理你的例行性工作排程呢?當然不需要,你只要編輯 /etc/crontab
這個文件就可以啦!有一點需要特別注意喔!那就是 crontab -e 這個 crontab 其實是/usr/bin/crontab 這個執行檔,但是 /etc/crontab 可是一個『純文本檔』喔!你可以 root 的身份編輯一下這個文件哩!
基本上,cron 這個服務的最低偵測限制是『分鐘
』,所以『 cron 會每分鐘去讀取一次 /etc/crontab 與/var/spool/cron 里面的數據內容
』,因此,只要你編輯完 /etc/crontab 這個文件,并且將他儲存之后,那么 cron 的設定就自動的會來執行了!
在 Linux 底下的 crontab 會自動的幫我們每分鐘重新讀取一次 /etc/crontab 的例行工作事項,但是某些原因或者是其他的 Unix 系統中,由于 crontab 是讀到內存當中的,所以在你修改完 /etc/crontab 之后,可能并不會馬上執行, 這個時候請重新啟動 crond 這個服務吧!『systemctl restart crond』
廢話少說,我們就來看一下這個 /etc/crontab 的內容吧!
[root@study ~]# cat /etc/crontab
SHELL=/bin/bash <==使用哪種 shell 接口
PATH=/sbin:/bin:/usr/sbin:/usr/bin <==執行文件搜尋路徑
MAILTO=root <==若有額外 STDOUT,以 email 將數據送給誰
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
看到這個文件的內容你大概就了解了吧!呵呵,沒錯!這個文件與將剛剛我們下達 crontab -e 的內容幾乎完全一模一樣!只是有幾個地方不太相同:
- MAILTO=root:
當 /etc/crontab 這個文件中的例行性工作的指令發生錯誤時,或者是該工作的執行結果有 STDOUT/STDERR 時,會將錯誤訊息或者是屏幕顯示的訊息傳給誰?默認當然是由系統直接寄發一封 mail 給 root 啦!不過, 由于 root 并無法在客戶端中以 POP3 之類的軟件收信,因此,鳥哥通常都將這個 e-mail 改成自己的賬號,好讓我隨時了解系統的狀況!例如:MAILTO=dmtsai@my.host.name - PATH=…:
這里就是輸入執行文件的搜尋路徑!使用默認的路徑設定就已經很足夠了! - 『分 時 日 月 周 身份 指令』七個字段的設定
這個 /etc/crontab 里面可以設定的基本語法與 crontab -e 不太相同喔!前面同樣是分、時、日、月、周五個字段, 但是在五個字段后面接的并不是指令,而是一個新的字段,那就是『執行后面那串指令的身份
』為何!這與使用者的 crontab -e 不相同。由于使用者自己的 crontab 并不需要指定身份,但 /etc/crontab 里面當然要指定身份啦!以上表的內容來說,系統默認的例行性工作是以 root 的身份來進行的
。
crond 服務讀取配置文件的位置
一般來說,crond 預設有三個地方會有執行腳本配置文件,他們分別是:
- /etc/crontab
- /etc/cron.d/*
- /var/spool/cron/*
這三個地方中,跟系統的運作比較有關系的兩個配置文件是放在 /etc/crontab
文件內以及/etc/cron.d/*
目錄內的文件, 另外一個是跟用戶自己的工作比較有關的配置文件,就是放在/var/spool/cron/
里面的文件群。 現在我們已經知道了 /var/spool/cron 以及 /etc/crontab 的內容,那現在來瞧瞧 /etc/cron.d 里面的東西吧!
[root@study ~]# ls -l /etc/cron.d
-rw-r--r--. 1 root root 128 Jul 30 2014 0hourly
-rw-r--r--. 1 root root 108 Mar 6 10:12 raid-check
-rw-------. 1 root root 235 Mar 6 13:45 sysstat
-rw-r--r--. 1 root root 187 Jan 28 2014 unbound-anchor
# 其實說真的,除了 /etc/crontab 之外,crond 的配置文件還不少耶!上面就有四個設定!
# 先讓我們來瞧瞧 0hourly 這個配置文件的內容吧!
[root@study ~]# cat /etc/cron.d/0hourly
# Run the hourly jobs
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
01 * * * * root run-parts /etc/cron.hourly
# 瞧一瞧,內容跟 /etc/crontab 幾乎一模一樣!但實際上是有設定值喔!就是最后一行!
如果你想要自己開發新的軟件,該軟件要擁有自己的 crontab 定時指令時,就可以將『分、時、日、月、周、身份、指令
』的配置文件放置到 /etc/cron.d/ 目錄下! 在此目錄下的文件是『crontab 的配置文件腳本
』。
請注意一下上面表格中提到的最后一行,每個整點的一分會執行『run-parts /etc/cron.hourly
』這個指令~咦!那什么是 run-parts 呢? 如果你有去分析一下這個執行檔,會發現他就是 shell script,run-parts 腳本會在大約 5 分鐘內隨機選一個時間來執行 /etc/cron.hourly 目錄內的所有執行文件
!因此,放在 /etc/cron.hourly/ 的文件,必須是能被直接執行的指令腳本, 而不是分、時、日、月、周的設定值喔!注意注意!
也就是說,除了自己指定分、時、日、月、周加上指令路徑的 crond 配置文件之外,你也可以
直接將指令放置到(或鏈接到)/etc/cron.hourly/ 目錄下
,則該指令就會被 crond 在每小時的 1 分開始后的5 分鐘內,隨機取一個時間點來執行啰!你無須手動去指定分、時、日、月、周
就是了。
但是眼尖的朋友可能還會發現,除了可以直接將指令放到 /etc/cron.hourly/ 讓系統每小時定時執行之外,在 /etc/ 底下其實還有 /etc/cron.daily/, /etc/cron.weekly/, /etc/cron.monthly/,那三個目錄是代表每日、每周、每月各執行一次的意思嗎?嘿嘿! 厲害喔!沒錯~是這樣~不過,跟 /etc/cron.hourly/ 不太一樣的是,那三個目錄是由 anacron 所執行的,而 anacron 的執行方式則是放在/etc/cron.hourly/0anacron
里面耶~跟前幾代 anacron 是單獨的 service 不太一樣喔!這部份留待下個小節再來討論。
最后,讓我們總結一下吧:
- 個人化的行為使用『 crontab -e 』:如果你是依據個人需求來建立的例行工作排程,建議直接使用 crontab -e 來建立你的工作排程較佳! 這樣也能保障你的指令行為不會被大家看到 (/etc/crontab 是大家都能讀取的權限喔!);
- 系統維護管理使用『 vim /etc/crontab 』:如果你這個例行工作排程是系統的重要工作,為了讓自己管理方便,同時容易追蹤,建議直接寫入 /etc/crontab 較佳!
- 自己開發軟件使用『 vim /etc/cron.d/newfile 』:如果你是想要自己開發軟件,那當然最好就是使用全新的配置文件,并且放置于 /etc/cron.d/ 目錄內即可。
- 固定每小時、每日、每周、每天執行的特別工作:如果與系統維護有關,還是建議放置到 /etc/crontab 中來集中管理較好。 如果想要偷懶,或者是一定要再某個周期內進行的任務,也可以放置到上面談到的幾個目錄中,直接寫入指令即可!
一些注意事項
有的時候,我們以系統的 cron 來進行例行性工作的建立時,要注意一些使用方面的特性。 舉例來說,如果我們有四個工作都是五分鐘要進行一次的,那么是否這四個動作全部都在同一個時間點進行?如果同時進行,該四個動作又很耗系統資源,如此一來,每五分鐘的某個時刻不是會讓系統忙得要死?呵呵!此時好好的分配一些運行時間就 OK 啦!所以,注意一下:
資源分配不均的問題
當大量使用 crontab 的時候,總是會有問題發生的,最嚴重的問題就是『系統資源分配不均
』的問題,以鳥哥的系統為例,我有偵測主機流量的信息,包括:
- 流量
- 區域內其他 PC 的流量偵測
- CPU 使用率
- RAM 使用率
- 在線人數實時偵測
如果每個流程都在同一個時間啟動的話,那么在某個時段時,我的系統會變的相當的繁忙,所以,這個時候就必須要分別設定啦!我可以這樣做:
[root@study ~]# vim /etc/crontab
1,6,11,16,21,26,31,36,41,46,51,56 * * * * root CMD1
2,7,12,17,22,27,32,37,42,47,52,57 * * * * root CMD2
3,8,13,18,23,28,33,38,43,48,53,58 * * * * root CMD3
4,9,14,19,24,29,34,39,44,49,54,59 * * * * root CMD4
看到了沒?那個『 , 』分隔的時候,請注意,不要有空格符!(連續的意思)如此一來, 則可以將每五分鐘工作的流程分別在不同的時刻來工作!則可以讓系統的執行較為順暢呦!
取消不要的輸出項目
另外一個困擾發生在『 當有執行成果或者是執行的項目中有輸出的數據時,該數據將會 mail 給MAILTO 設定的賬號 』,好啦,那么當有一個排程一直出錯(例如 DNS 的偵測系統當中,若 DNS 上層主機掛掉,那么你就會一直收到錯誤訊息!)怎么辦?呵呵!還記得數據流重導向吧? 直接以『數據流重導向』將輸出的結果輸出到 /dev/null 這個垃圾桶當中就好了!
安全的檢驗
很多時候被植入木馬都是以例行命令的方式植入的,所以可以藉由檢查 /var/log/cron 的內容來視察是否有『非您設定的 cron 被執行了?』這個時候就需要小心一點啰!
周與日月不可同時并存
另一個需要注意的地方在于:『你可以分別以周或者是日月為單位作為循環,但你不可使用「幾月幾號且為星期幾」的模式工作
』。 這個意思是說,你不可以這樣編寫一個工作排程:
30 12 11 9 5 root echo "just test" <==這是錯誤的寫法
本來你以為九月十一號且為星期五才會進行這項工作,無奈的是,系統可能會判定每個星期五作一次,或每年的 9 月 11 號分別進行
,如此一來與你當初的規劃就不一樣了~所以啰,得要注意這個地方!
28.5 可喚醒停機期間的工作任務
想象一個環境,你的 Linux 服務器有一個工作是需要在每周的星期天凌晨 2 點進行,但是很不巧的,星期六停電了~所以你得要星期一才能進公司去啟動服務器。 那么請問,這個星期天的工作排程還要不要進行?因為你開機的時候已經是星期一,所以星期天的工作當然不會被進行,對吧!
問題是,若是該工作非常重要 (例如例行備份), 所以其實妳還是希望在下個星期天之前的某天還是進行一下比較好~那你該怎辦?自己手動執行?如果你跟鳥哥一樣是個記憶力超差的家伙,那么肯定『記不起來某個重要工作要進行』的啦! 這時候就得要靠 anacron 這個指令的功能了!這家伙可以主動幫你進行時間到了但卻沒有執行的排程喔!
什么是 anacron
anacron 并不是用來取代 crontab 的,anacron 存在的目的就在于我們上頭提到的,在處理非 24 小時一直啟動的 Linux 系統的 crontab 的執行! 以及因為某些原因導致的超過時間而沒有被執行的排程工作。
其實 anacron 也是每個小時被 crond 執行一次,然后 anacron 再去檢測相關的排程任務有沒有被執行,如果有超過期限的工作在, 就執行該排程任務,執行完畢或無須執行任何排程時,anacron 就停止了。
由于 anacron 預設會以一天、七天、一個月為期去偵測系統未進行的 crontab 任務,因此對于某些特殊的使用環境非常有幫助。 舉例來說,如果你的 Linux 主機是放在公司給同仁使用的,因為周末假日大家都不在所以也沒有必要開啟, 因此你的 Linux 是周末都會關機兩天的。但是 crontab 大多在每天的凌晨以及周日的早上進行各項任務, 偏偏你又關機了,此時系統很多 crontab 的任務就無法進行。anacron 剛好可以解決這個問題!
那么 anacron 又是怎么知道我們的系統啥時關機的呢?這就得要使用 anacron 讀取的時間記錄文件(timestamps) 了! anacron 會去分析現在的時間與時間記錄文件所記載的上次執行 anacron 的時間,兩者比較后若發現有差異, 那就是在某些時刻沒有進行 crontab 啰!此時 anacron 就會開始執行未進行的 crontab 任務了!
anacron 與 /etc/anacrontab
anacron 其實是一支程序并非一個服務!這支程序在 CentOS 當中已經進入 crontab 的排程喔!同時anacron 會每個小時被主動執行一次喔! 咦!每個小時?所以 anacron 的配置文件應該放置在/etc/cron.hourly/
嗎?嘿嘿!您真內行~趕緊來瞧一瞧:
[root@study ~]# cat /etc/cron.hourly/0anacron
#!/bin/sh
# Check whether 0anacron was run today already
if test -r /var/spool/anacron/cron.daily; thenday=`cat /var/spool/anacron/cron.daily`
fi
if [ `date +%Y%m%d` = "$day" ]; thenexit 0;
fi
# 上面的語法在檢驗前一次執行 anacron 時的時間戳!
# Do not run jobs when on battery power
if test -x /usr/bin/on_ac_power; then/usr/bin/on_ac_power >/dev/null 2>&1if test $? -eq 1; thenexit 0fi
fi
/usr/sbin/anacron -s
# 所以其實也僅是執行 anacron -s 的指令!因此我們得來談談這支程序!
基本上, anacron 的語法如下:
[root@study ~]# anacron [-sfn] [job]..
[root@study ~]# anacron -u [job]..
選項與參數:
-s :開始一連續的執行各項工作 (job),會依據時間記錄文件的數據判斷是否進行;
-f :強制進行,而不去判斷時間記錄文件的時間戳;
-n :立刻進行未進行的任務,而不延遲 (delay) 等待時間;
-u :僅更新時間記錄文件的時間戳,不進行任何工作。
job :由 /etc/anacrontab 定義的各項工作名稱。
在我們的 CentOS 中,anacron 的進行其實是在每個小時都會被抓出來執行一次, 但是為了擔心anacron 誤判時間參數,因此/etc/cron.hourly/ 里面的 anacron 才會在檔名之前加個 0 (0anacron),讓anacron 最先進行!就是為了讓時間戳先更新!以避免 anacron 誤判 crontab 尚未進行任何工作的意思。
接下來我們看一下 anacron 的配置文件: /etc/anacrontab 的內容好了:
[root@study ~]# cat /etc/anacrontab
SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
RANDOM_DELAY=45 # 隨機給予最大延遲時間,單位是分鐘
START_HOURS_RANGE=3-22 # 延遲多少個小時內應該要執行的任務時間
1 5 cron.daily nice run-parts /etc/cron.daily
7 25 cron.weekly nice run-parts /etc/cron.weekly
@monthly 45 cron.monthly nice run-parts /etc/cron.monthly
天數 延遲時間 工作名稱定義 實際要進行的指令串
# 天數單位為天;延遲時間單位為分鐘;工作名稱定義可自定義,指令串則通常與 crontab 的設定相同!
[root@study ~]# more /var/spool/anacron/*
::::::::::::::
/var/spool/anacron/cron.daily
::::::::::::::
20150731
::::::::::::::
/var/spool/anacron/cron.monthly
::::::::::::::
20150703
::::::::::::::
/var/spool/anacron/cron.weekly
::::::::::::::
20150727
# 上面則是三個工作名稱的時間記錄文件以及記錄的時間戳
我們拿 /etc/cron.daily/ 那一行(1 5 cron.daily nice run-parts /etc/cron.daily
)的設定來說明好了。那四個字段的意義分別是:
- 天數:anacron 執行當下與時間戳 (/var/spool/anacron/ 內的時間紀錄文件) 相差的天數,若超過此天數,就準備開始執行,若沒有超過此天數,則不予執行后續的指令。
- 延遲時間:若確定超過天數導致要執行排程工作了,那么請延遲執行的時間,因為擔心立即啟動會有其他資源沖突的問題吧!
- 工作名稱定義:這個沒啥意義,就只是會在 /var/log/cron 里頭記載該項任務的名稱這樣!通常與后續的目錄資源名稱相同即可。
- 實際要進行的指令串:有沒有跟 0hourly 很像啊!沒錯!相同的作法啊!透過 run-parts 來處理的!
根據上面的配置文件內容,我們大概知道 anacron 的執行流程應該是這樣的 (以 cron.daily 為例):
- 由 /etc/anacrontab 分析到 cron.daily 這項工作名稱的天數為 1 天;
- 由 /var/spool/anacron/cron.daily 取出最近一次執行 anacron 的時間戳;
- 由上個步驟與目前的時間比較,若差異天數為 1 天以上 (含 1 天),就準備進行指令;
- 若準備進行指令,根據 /etc/anacrontab 的設定,將延遲 5 分鐘 + 3 小時 (看 START_HOURS_RANGE 的設定);
- 延遲時間過后,開始執行后續指令,亦即『 run-parts /etc/cron.daily 』這串指令;
- 執行完畢后, anacron 程序結束。
如此一來,放置在 /etc/cron.daily/ 內的任務就會在一天后一定會被執行的!因為 anacron 是每個小時被執行一次嘛! 所以,現在你知道為什么隔了一陣子才將 CentOS 開機,開機過后約 1 小時左右系統會有一小段時間的忙碌!而且硬盤會跑個不停!那就是因為 anacron 正在執行過去/etc/cron.daily/, /etc/cron.weekly/, /etc/cron.monthly/ 里頭的未進行的各項工作排程啦!這樣對 anacron 有沒有概念了呢? ^_^
最后,我們來總結一下本章談到的許多配置文件與目錄的關系吧!這樣我們才能了解 crond 與anacron 的關系:
- crond 會主動去讀取 /etc/crontab, /var/spool/cron/*, /etc/cron.d/* 等配置文件,并依據『分、時、日、月、周』的時間設定去各項工作排程;
- 根據 /etc/cron.d/0hourly 的設定,主動去 /etc/cron.hourly/ 目錄下,執行所有在該目錄下的執行文件;
- 因為 /etc/cron.hourly/0anacron 這個腳本文件的緣故,主動的每小時執行 anacron ,并呼叫 /etc/anacrontab 的配置文件;
- 根據 /etc/anacrontab 的設定,依據每天、每周、每月去分析 /etc/cron.daily/, /etc/cron.weekly/, /etc/cron.monthly/ 內的執行文件,以進行固定周期需要執行的指令。
也就是說,如果你每個周日的需要執行的動作是放置于 /etc/crontab 的話,那么該動作只要過期了就過期了,并不會被抓回來重新執行。但如果是放置在 /etc/cron.weekly/ 目錄下,那么該工作就會定期,幾乎一定會在一周內執行一次~如果你關機超過一周,那么一開機后的數個小時內,該工作就會主動的被執行喔! 真的嗎?對啦!因為 /etc/anacrontab 的定義啦!
基本上,crontab 與 at 都是『定時』去執行,過了時間就過了!不會重新來一遍~那anacron 則是『定期』去執行,某一段周期的執行~ 因此,兩者可以并行,并不會互相沖突啦!
該系列目錄 --> 【BASH】回顧與知識點梳理(目錄)