預時排程 at/cron/anacron
管理系統,必定會有機會來使用到預時排程以減輕工作負擔。
本文節錄自鳥哥的 Linux 私房菜,做為筆者自己快速參查用。請至鳥哥的網頁有完整詳盡豐富的教學內容。除了鳥哥,Netman 的網站也是學習 Linux 的好去處。
at/batch/crontab/anacrontab
tab 是指 table 表格的意思,就是以表格的形式做規劃。
at
# 一次性的預約時間執行某項任務。
# at [-mldv] TIME
# 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 環境,讓你下達多重指令等待運作!
# at 的執行與終端機環境無關,而所有 standard output/standard error output 都會傳送到執行者的 mailbox 去,所以在終端機當然看不到任何資訊。那怎辦?沒關係, 可以透過終端機的裝置來處理!假如你在 tty1 登入,則可以使用『 echo "Hello" > /dev/tty1 』來取代。
範例一:查詢目前主機上面有多少的 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
# 沒有任何資訊,表示該工作被移除了!
# batch 與 at 不同之處,會在 CPU 的工作負載小於 0.8 的時候,才進行所下達的工作任務
# at 與 cron 都同樣,以優先順序來說, /etc/cron.allow 比 /etc/cron.deny 要優先,而在判斷上,這兩個檔案只選擇一個來限制而已/一滿足即行,因此,建議你只要保留一個即可, 免得影響自己在設定上面的判斷
- 說明:
- /var/spool/cron/atjobs/$encoded, at 建立任務所存放的地方。
- /var/spool/cron/crontabs/$username 則是 cron 建立任務所存放的地方;並且這是專用於使用者的定時任務,透過下達 crontab -e 來建立編輯。
- 至於系統自身也有一份專用的定時任務表格異於前述,系統的例行性任務透過編輯 /etc/crontab 這個檔案;當中的任務,會在指令前多一個使用者名稱欄位(所以通常是 root)。也因此,修改完 /etc/crontab 之後,請重新啟動 crond 這個服務吧!『systemctl restart crond』
- 此外還有另一處也是系統層級用,存放預時表格的地方 /etc/cron.d/。
- 與 cron 相關還需提及的是,在 /etc/cron.hourly/,/etc/cron.daily/,/etc/cron.weekly/,/etc/cron.monthly/,這四個資料夾內的所有 script files 批次執行檔/腳本執行檔,就是依照前述的系統預時任務檔的設定,(必然地)適時分別執行。所以無關乎 cron;我們可直接將某腳本置於相應的的資料夾,該腳本便會適時被執行了。
- 前述 /etc/cron.hourly/ 是由 cron 所執行。其餘三個則是由 anacron 來執行之,其當中都有一個 0anacron 的檔案,其目的都是更新其所屬的時間上的 timestamps。
- /etc/at.allow,/etc/at.deny 限制哪些使用者可使用 at。
- 如果兩個檔案都不存在,那麼只有具 root 權限的可以使用 at 這個指令。
- /etc/cron.allow,/etc/cron.deny 限制哪些使用者可使用 cron。
- 如果 cron.deny 檔案不存在,那麼任何使用者都可以使用 crontab 這個指令。
- 表格的最後一行之後再留一空行,不然那最後一行排程有可能無法成功執行。
- 表格中出現的 run-parts 這個執行命令,會去執行所指定的目錄下的所有可執行檔。因 crontab 的表格中每一行只接一執行行,所以 run-parts 便帶來了之一擴展性。
- Cron 在 Ubuntu 上預設的行為,從 /etc/crontab 中看出,若已有安裝 anacron,便交由 anacron 管理 /etc/cron.*/ 這幾個目錄下的執行,不然,就自己會去執行。因此,在 /etc/anacrontab 中的預設,便是必然執行 /etc/cron.*/。
crontab
# 使用者的定時任務,下達 crontab -e 來建立編輯。
# 當使用者使用 crontab 這個指令來建立工作排程之後,該項工作就會被紀錄到 /var/spool/cron/crontabs/ 裡面去了,而且是以帳號來作為判別的喔!舉例來說, dmtsai 使用 crontab 後, 他的工作會被紀錄到 /var/spool/cron/crontabs/dmtsai 裡頭去!但請注意,最好是透過 crontab 命令,而不要使用 vi 直接去編輯該檔案, 因為可能由於輸入語法錯誤,會導致無法執行 cron 喔!另外, cron 執行的每一項工作都會被紀錄到 /var/log/cron 這個登錄檔中
[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
#分 時 日 月 週 |<==============指令串========================>|
比較有趣的是那個『週』喔!週的數字為 0 或 7 時,都代表『星期天』的意思!另外,還有一些輔助的字符,大概有底下這些:
@yearly,@monthly,@weekly,@daily
@reboot
不過建議用能較準確的時間,畢竟一天或一週很長也不知其何時執行。
代表意義 | 分鐘 | 小時 | 日期 | 月份 | 週 | 指令 |
數字範圍 | 0-59 | 0-23 | 1-31 | 1-12 | 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 ,相同意思! |
anacron
anachronistic 過時的。
在 /etc/anacrontab 中記錄逾時設定。cron 的最小時間單位是分鐘,anacron 是天數。 另外,只有系統管理者權限才能使用 /etc/anacrontab。
[root@study ~]# anacron [-sfn] [job]..
[root@study ~]# anacron -u [job]..
選項與參數:
-s :開始一連續的執行各項工作 (job),會依據時間記錄檔的資料判斷是否進行;
-f :強制進行,而不去判斷時間記錄檔的時間戳記;
-n :立刻進行未進行的任務,而不延遲 (delay) 等待時間;
-u :僅更新時間記錄檔的時間戳記,不進行任何工作。
job :由 /etc/anacrontab 定義的各項工作名稱。
# 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
訊息提醒
- at 的話,
- 可使用 notify-send ‘標題’ ‘訊息內容’,可在桌面上秀出短暫的訊息。
- 例如 notify-send ‘This is an at-command’ ‘這是 at 排程’
- 加上 -u critical 參數可保持在桌面上直到按下它。
To Do
- Crontab 的訊息提醒:筆者搜出來的結果似乎都需用到 script file。因此您也可試著去找尋最簡便的訊息提醒方式。
- Anacrontab 的細節:因此在 Ubuntu 上,cron/anacron 預設都已安裝,是不是只要用 crontab -e 來排程即可,若逾時未執行 anacron 會介入。請自行查證。(答案是:否定的 by 筆者試),接下來看,
- 因為使用 anacron 要等上一天才能知道結果,所以筆者竄改了時間戳記推前一天(此舉有疑慮勿輕試)並下達了 sudo anacron -n cron.daily 但筆者的 crontab -e 那行任務並未執行。
- 所以仔細追溯上面 anacrontab 的用法,它是有與 /etc/crontab 屬於系統層級的排程對應的,所以看來是要編輯這份檔案了。
- 結果可惜的是,筆者在 /etc/crontab 中加了行每天執行的任務,並使過時後前推戳記一天,再下指令 anacron 來查行,結果仍然沒執行。(除了 /etc/crontab 中那行任務,重啟 cron 後,本文提到所有相關的地方或檔案都無變化,即也就只有那行任務記載在那)
- 結論筆者猜測,應要仿照 crontab/anacrontab 的那三項 cron.daily 等,乃至於還要再追加戳記檔等如此的設定方式吧。要不然最簡便的方式,在 /etc/cron.daily/ 等目錄下放置 script file,則必然萬無一失。
- 最後,提醒只有 daily 或以多的時間,anacron 才會介入。hourly 也只由 cron 負責。預時排程的任務內容,最好是無關乎時基,即,同一時距內重覆執行或少執行幾次也不影響正確性。
範例
我們先用一段話來描述預設下整個機制:
Cron 是個 daemon,每個小時執行一次並檢查相關的預時設定檔:/etc/crontab,/etc/cron.d/*,/var/spool/cron/crontabs/*。在 Ubuntu 的預設狀態下既存生效的四種重要的預時行程:每天早上確認一次 anacron 有在待命,每天 ./cron.daily/*,每週 ./cron.weekly/*,及每月 ./cron.monthly/*(cron.hourly 內並沒有檔案)。不過這後面三種並非親自由 cron 來執行,而是交由 anacron 來做以實現逾時執行,除非並未安裝有 anacron 才 cron 自己來。
筆者需提醒一下,以上預時設定皆與我們無關;系統自己需要的。
與我們相關的是透過 crontab -e 或編輯 /etc/crontab,但卻都不會有 anacron 幫忙。因此我們便想問,如何透過 crontab -e 建立預時任務且可逾時執行/前題是需 hourly 以外的。因此分成兩個問題:A. 週期至少 daily。B. 某時單次(留意當下 anacron 應已執行過當天的份了)。
A. 週期至少 daily
如前述,將 script file 直接置入 ./cron.daily/ 等資料夾內即可。
B. 某時單次
- 我們會有確切的時間點某日期的幾點幾分。Cron 執行了,固然沒有問題。萬一沒執行,該行任務便從此被忽略。因此,關鍵角色在 anacron;問題是,anacron 是每天的週期動物。。。
- 若單在 cron/anacron 的邏輯下,所有能做的,真無法實現我們此處要的。原因是,在哪個時間點執行某任務,唯一記載在使用者預時任務檔中,唯有 cron 知道。若一旦被執行了,我們始知;若尚不須執行或錯失執行,其現況無法區分,因此我們無從知道乃至於下手。
- (以下會出現兩個名詞 :監管任務,執行任務 [即兩個 script-file 檔案])
- 循解:因此,我們必然會在 ./cron.daily/ 中加入一個監管的任務,做什麼事我不知道。畢竟,anacron 的利用價值也只有這麼多。
- crontab -e 的編輯檔案內,可放單行(複合)指令,但若讓它去執行任務的 script file 對我們會方便很多(因為單純且統一)。第一行我們就命名 1.sh,第二行就命名 2.sh 以此類推。
- 老手有其高效的方法,筆者新手沒辦法,只能開個資料夾暫存些東西,用以判斷。並存放我們要執行的任務。其可能額外的好處是 cron 沒執行它,anacron 可接手(意指我們放在 ./cron.daily/監管的 script-file 所做的事)。
- 預時任務日期是確定的。監管的到期日須往後推一天,因為若為當天的話可能會被重覆/提早執行。(但寫時間戳記檔時仍使用到期日,因監管任務檔內已設定為後推一天了)
- 因此思路的第一步便是不得不把預時任務日期再明載在另一處我們須自行比對,逾期便交由 anacron 執行(由監管任務去呼叫執行任務)。否則順利的話,cron 必定會執行因為我們會讓它執行後刪除該明載以避免監管任務再比出了逾期結果又再跑一次。
- 接下來,就實作如下:
- mkdir -p ~/.myanacron/jobs 存放執行任務
- mkdir -p ~/.myanacron/timestamps 存放日期戳記
- touch ~/.myanacron/my-ana-monitor.sh 監管任務
- 監管任務的內容,請見下面段落,gedit ~/.myanacron/my-ana-monitor.sh
#!/bin/sh
# 這是置於 $HOME/.myanacron/my-ana-monitor.sh,並須將它複製到 /etc/cron.daily/
# 用以監控在 $HOME/.myanacron/timestamps/ 底下的日期戳記檔,例如 1.sh.date
# 而在 $HOME/.myanacron/jobs/ 底下則是執行任務檔,例如 1.sh
# 當逾期時,這邊便會執行該任務。
# 因此使用者必須在編輯完成“執行任務.sh”,“預時設定”後,建立日期戳記:
# echo `date +%Y%m%d` > $HOME/.myanacron/timestamps/執行任務.sh.date
# 還有這是由 root 來執行的,所以須以 root 的角度來看路徑或執行結果等權限問題
MYHOME=/home/ken
basepath="${MYHOME}/.myanacron"
alljobfiles=`ls ${MYHOME}/.myanacron/jobs/`
for eachfile in ${alljobfiles}
do
tfile="${basepath}/timestamps/${eachfile}.date"
if [ -e ${tfile} ]; then
# echo "checking timestamp file: ${tfile}"
today=$(date +%Y%m%d)
if [ `cat ${tfile}` -lt ${today} ]; then
mv "${tfile}" "${tfile}.done"
${basepath}/jobs/${eachfile}
fi;
fi;
done
- 當 my-ana-monitor.sh 建立好之後,
- sudo chmod 755 $HOME/.myanacron/my-ana-monitor.sh
- sudo cp $HOME/.myanacron/my-ana-monitor.sh /etc/cron.daily
- sudo chown root:root /etc/cron.daily/my-ana-monitor.sh
- 請特別注意,該目錄下,root 不會去執行 *.sh 的檔案,故需更名不帶 .sh 的!
- sudo mv /etc/cron.daily/my-ana-monitor.sh /etc/cron.daily/my-ana-monitor
- 如此就算是安裝好了,接下來如何使用:
- crontab -e
- 加入一行例如,在 1 月 25 日 21 點 30 分執行 1.sh:(可把 1.sh 代換成您的 script file)
- 30 21 25 1 * $HOME/.myanacron/jobs/1.sh && mv -f $HOME/.myanacron/timestamps/1.sh.date $HOME/.myanacron/timestamps/1.sh.date.done
- 接著産生戳記檔,可以直接 echo 20200125 > $HOME/.myanacron/timestamps/1.sh.date
- 或 echo `date +%Y%m%d` > $HOME/.myanacron/timestamps/1.sh.date
- 最後,任務檔,用最簡單的在桌面産生一個檔案:
- echo touch ~/Desktop/job1done.txt > $HOME/.myanacron/jobs/1.sh
- chmod u+x $HOME/.myanacron/jobs/1.sh
- 結論:本節的重點是,任務需在精準的時間點被執行。萬一錯失了這個機會,我們仍能保證在隔天或更久之後的一次開機後,會被補執行一次。
- 補充,幾天後,例如 100 天後,我們可以如此來查詢:
- date –date=”100 days” “+%Y%m%d”(注意雙引號及 – -d)
- 參考資料
- https://steve-parker.org/
- https://askubuntu.com/questions/518993/who-runs-scripts-inside-etc-cron-hourly-if-anacron-is-enabled
發佈留言