作者:陳柏菁 E-mail:pachingko@ms96.url.com.tw
第八章 排程工作

索引:
8.1 crontab 排程
  8.1.1 crontab 所需套件及套件內容
  8.1.2 設定 crontab 排程 ---
使用 crontab 指令建立排程
編輯排程設定檔 (/etc/crontab/etc/cron.d/*)
限定使用者執行 crontab (/etc/cron.deny/etc/cron.allow)
8.2 at 排程
  8.2.1 at 所需套件及套件內容
  8.2.2 設定 at 排程 ---
使用 at 指令建立 at 排程
at 相關檔案
使用 batch 指令建立 at 排程


 如果您是一個系統管理者,相信每天都會有大大小小的事情等著您去處理,所以有時候難免會遺忘一些例行性要執行的工作,比如備份計劃、分析系統紀錄檔、清除不必要的暫存檔、列印大檔案 … 等等 ﹔而有些工作在進行時,或許會耗用較多的系統資源,因此您可能會想在系統負載較低時才進行這些工作,那最佳時段應該就是在夜深人靜的凌晨時分了,這時候聰明的你可能已經想到把這些工作給它編入排程,這樣一來,當所指定執行排程的時間一到,系統就會自動幫我們去做這些事情。

 在 Linux 上要編寫排程時,常見到的有 crontab 及 at 兩種方式,不過兩者可是有差別的噢。利用 crontab 所設計的排程工作會週期性 (periodic) 的執行,只要您不將它終止,就會永無止境的執行下去 ﹔至於 at 排程則只會在您指定的時間 (particular time) 執行那麼一次而已,執行完畢就沒了。緊接著就來介紹如何設計 crontab 及 at 排程。

8.1 crontab 排程

8.1.1 crontab 所需套件及套件內容

 先確定 cron 套件有安裝,並檢視一下套件內容:

suse:~ # rpm -qa | grep cron
cron-4.1-45.4

suse:~ # rpm -ql cron
/etc/crontab 排程設定檔。只有管理者可以將排程工作設定在這裡。
/etc/init.d/cron 管理排程服務的 script。
/etc/cron.deny 設定拒絕執行 crontab 指令的使用者名單。
/usr/bin/crontab 編寫排程工作的指令。
/usr/sbin/cron 提供排程服務的 daemon。
/usr/sbin/rccron 為一符號連結檔,連結至 /etc/init.d/cron。
/var/spool/cron/tabs 執行 crontab 指令所編寫好的排程,會寫入此目錄下的檔案內。

註:所謂的 daemon,就是泛指那些提供服務的程式。

 crontab 排程工作中的執行主程式為 /usr/sbin/cron,而當 cron 啟動後,預設每分鐘都會去自動載入相關的檔案一次,如 /etc/crontab、/var/spool/cron/tabs/*、/etc/cron.d/* 等,所以當您編寫好排程工作後,不需要重新啟動 cron script,是不是很方便呢 !

8.1.2 設定 crontab 排程

 編寫 crontab 排程的方式,一般常用到的有以下幾種:

  1. 使用 crontab 指令。
  2. 將排程工作設定在 /etc/crontab 或 /etc/cron.d 目錄下的檔案。
  3. 於 /etc/cron.hourly、/etc/cron.daily、/etc/cron.weekly、/etc/cron.monthly 等目錄中,安置您事先寫好的 scripts。
 最後一種方式應該很好理解,比如說您希望某些 scripts 能每天或每週被執行的話,那就分別把它們安置在 /etc/cron.daily 及 /etc/cron.weekly 目錄下即可。因此以下只教大家如何利用前面兩種方式來編輯 crontab 排程。

使用 crontab 指令建立排程

 每個使用者預設都可以執行這個指令來編寫屬於自己的排程工作。

指令語法
crontab [-u user] file
crontab [-u user] {-l|-r|-e}

參數說明
-u 指定要編輯、列出或移除哪個使用者的 crontab 排程。
-e 編輯 (edit) 排程工作。
-l 列出 (list) 排程工作。
-r 移除 (remove) 排程工作。

 當執行 "crontab -e" 時,就是在編輯自己的排程工作,而在您按下 [Insert] 鍵以後就可以開始做編輯了,完成後輸入 ":wq" 存檔離開即可。

 再來認識一下 crontab 的設定格式:

設定欄位 分鐘 小時 日期 月份 星期 執行工作
設定範圍 0-59 0-23 1-31 1-12 0-7 command

 前面五個欄位是設定執行排程的時間,最後一個欄位就是您要執行的工作,可以是一些程式的組合或者是 script。另外星期的那個欄位如果是 0 或 7,就代表是星期天。

 在時間欄位裡,可以額外使用一些符號來讓時間的設定更具有彈性,茲列舉如下:

符號 代 表 意 義
- 表示一段連續時間範圍的符號,比如在月份欄位輸入 3-6,就代表 3、4、5、6 月。
, 個別指定時間的分隔符號,比如在星期欄位輸入 3,6,就代表星期三及星期六。
* 表示所有時間的符號,比如在分鐘欄位輸入 *,就代表每一分鍾。
/ 其後需指定一數字,表示每間隔多久時間之意,比如在小時欄位輸入 0-23/2,就代表 0、2、4、6、… 、22 時之意。

 接著請看以下的基本範例:

範例一:在每年的十二月二十日下午四點三十分執行排程工作。

    30  16  20  12  *  程式

範例二:在每個月的二十日下午四、五、六點三十分執行排程工作。

    30  16-18  20  *  *  程式

範例三:在 12/5~12/26 期間,每隔三天的晚上十一點十分執行排程工作。

    10  23  5-26/3  12  *  程式

範例四:在星期三及星期六的凌晨兩點二十分執行排程工作。

    20  02  *  *  3,6  程式

範例五:每隔五分鐘執行一次排程工作。

    */5 * * * * 程式

範例說明
suse:~ # crontab -e
12 23 * * 3,6 tar zcvf /backup/bck.tgz /home /etc
10 22 * *  *  cp -a /var/spool/mail /backup

# 第一行設定是說,於周三及周六晚間十一點十二分執行備份工作 ﹔如您沒指定
# bck.tgz 的路徑,那麼預設就會建立在自己的家目錄中。
# 下一行的設定是說,每天晚間十點十分備份 /var/spool/mail 目錄。

suse:/var/spool/cron/tabs # cat root
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (/tmp/crontab.5037 installed on Sun Sep 18 17:11:12 2006)
# (Cron version -- $Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $)
12 23 * * 3,6 tar zcvf /backup/bck.tgz /home /etc
10 22 * *  *  cp -a /var/spool/mail /backup

# 當 root 使用 crontab 指令所編輯好的排程會寫入 /var/spool/cron/tabs/root 檔案中。

suse:~ # crontab -l
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (/tmp/crontab.5037 installed on Sun Sep 18 17:11:12 2006)
# (Cron version -- $Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $)
12 23 * * 3,6 tar zcvf /backup/bck.tgz /home /etc
10 22 * *  *  cp -a /var/spool/mail /backup

# 列出排程工作內容。您會發現跟上面的內容一模一樣,因這些資料就是從那個檔案來讀出的。

suse:~ # crontab -r
# 清除剛剛您所編輯的所有 crontab 排程。
# 如只想移除部分排程工作的話,就執行 "crontab -e" 進去將其刪除即可。

suse:~ # crontab -l
no crontab for root

# 確定已經移除了噢。

suse:~ # crontab -u barry -e
# 管理者幫使用者 barry 編輯排程。

# 以下範例是使用者 barry 事先將欲執行的工作設定在檔案內,然後再配合 crontab 使用:
barry@suse:~> vi cronfile
30 14 * * 5 cat mailfile | mail mary tina

barry@suse:~> crontab cronfile
barry@suse:~> crontab -l
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (cronfile installed on Sun Sep 18 19:20:30 2006)
# (Cron version -- $Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $)
30 14 * * 5 cat mailfile | mail mary tina

 剛剛最後一個範例,是以一般使用者的身分去編排程,然後再以 "crontab -l" 去存取 /var/spool/cron/tabs/barry 的內容。或許您會想說那乾脆直接去編輯或瀏覽這個檔案不就行了嗎,但實際上是不可行的,請檢查一下 /var/spool/cron 的權限就知道為什麼了:

barry@suse:~> ls -ld /var/spool/cron
drwx------ 4 root root 96  Oct 16 22:49 /var/spool/cron

 看到了嗎 ? 其他人 (others) 對這個目錄根本不具任何權限。那既然這樣又為何可以使用指令的方式來寫入及存取呢 ? 再查看一下 crontab 程式的權限:

barry@suse:~> ls -l /usr/bin/crontab

-rwsr-xr-x 1 root trusted 33260 Jun 16 21:37 /usr/bin/crontab

 原來 crontab 程式具有 SUID 的屬性,這下子總該恍然大悟了吧 !

編輯排程設定檔

 管理者可以直接去編輯排程的設定檔,至於編輯的格式跟我們使用 crontab 指令去編輯時差不多,只不過多了個執行身份的設定而已。以下會分別在 /etc/crontab 檔案及 /etc/cron.d/ 目錄中去編輯排程。

  編輯 /etc/crontab
   
suse:~ # vi /etc/crontab
SHELL=/bin/sh 
# 指定程式執行時所使用的解析器。

PATH=/usr/bin:/usr/sbin:/sbin:/bin:/usr/lib/news/bin 
# 設定執行程式所引用的路徑。

MAILTO=root 
# 將排程中,執行程式的 stdout 或 stderr 訊息寄給 root。

# check scripts in cron.hourly, cron.daily, cron.weekly, and cron.monthly

-*/15 * * * *  root   test -x /usr/lib/cron/run-crons && /usr/lib/cron/run-crons >/dev/null 2>&1
# run-crons 這支 script,主要是檢查 /etc 下的 cron.hourly、cron.daily、
# cron.weekly cron.monthly 目錄裡的 scripts 需不需要被執行,
# 且每 15 分鐘 run-crons 就會檢查一次。另外 UID 為 0 者,可以在排程紀錄
# 的最前頭加上 "-" 符號, 表示不會把該程式執行訊息紀錄下來。


30 2 * * *  root /bin/tar zcvf /backup/bck.`date +\%m-\%d`.tgz /home /etc

# 這是筆者所新增的一筆排程工作。

在剛剛 /etc/crontab 裡新增了一個備份的排程工作,並在備份檔的檔名中加上了日期的顯示,如此一來,就可以讓每天所產生的備份檔名稱都不相同。如果您也想這麼做的話,那 date 這個指令的基本用法可就要學一下了:

suse:~ # date       
Sat Jan 20 16:30:18 CST 2007
# 顯示目前的日期時間。

suse:~ # date 012115202007
Sun Jan 21 15:20:00 CST 2007
# 修改系統 (作業系統) 時間。
# date 指令後所指定者為月(01)、日(21)、時 (15)、分 (20)、年 (2007)。


suse:~ # date +%Y-%m-%d--%k:%M
2007-01-21--15:26
# %Y 一直到最後面的 %M,依序分別代表西元年、月、日、時、分。

一般在命令列上執行 date 指令並於其後指定要顯示的時間單位時,不需在 "%" 前加上 backslash ( \ ),但是如果設定在排程之中,就一定要加上 " \ " ,否則此排程工作會無法執行。不然您乾脆將要執行的指令事先寫在 scripts 裡,然後再把此 script 放入 /etc/crontab 也行:

suse:~ # vi bck.sh
#! /bin/bash

/bin/tar zcvf /backup/bck.`date +%m-%d`.tgz /home /etc  
# "%" 之前,不需加上 "\"。

suse:~ # chmod +x bck.sh

suse:~ # vi /etc/crontab
30 2 * * *  root  /root/bck.sh

這樣就可以搞定了。
     
  編輯 /etc/cron.d/*
    這是另一個可以編寫排程的地方,您可於此目錄下建立排程檔案,至於檔案內容的設定格式與 /etc/crontab 是相同的:

suse:~ # vi /etc/cron.d/cronfile
30 23 * * * root /bin/tar zcvf /root/test.`date +\%m-\%d`.tgz /home /var /etc

限定使用者執行 crontab

 系統預設所有使用者都能執行 crontab 指令,來設定自己的排程工作,因此如果對這方面想要稍做限制的話,可以利用 /etc/cron.deny 及 /etc/cron.allow 這兩個檔案。

  /etc/cron.deny
    欲拒絕部分使用者執行 crontab 指令,則可將這些使用者名單寫入此檔中。比如想拒絕使用者 barry 及 tina 執行 crontab,就把這兩個使用者設定進去:

suse:~ # vi /etc/cron.deny
barry
tina


這樣除了 barry 及 tina 不能執行 crontab 外,其他人則是會被允許的。
     
  /etc/cron.allow
    只想允許少數使用者執行 crontab 指令,則可設定在 /etc/cron.allow 中。

suse:~ # vi /etc/cron.allow
barry
mary

這樣除了 barry 及 mary 可以執行 crontab 外,其他人 (root 除外) 則是會被拒絕的。

 當 /etc/cron.allow 檔案存在時,是會以這個檔案的設定為主,只有在 cron.allow 不存在時,才會以 cron.deny 為主。比如上面兩個範例中,cron.allow 及 cron.deny 檔案裡都有 barry,那最後 barry 當然是會被允許的。由以上的解說不難發現,當 cron.allow 及 cron.deny 都同時存在時,實際上在 cron.deny 中的設定是沒什麼效果的。

    
8.2 at 排程

8.2.1 at 所需套件及套件內容
 
 先確定 at 套件有安裝,並檢視一下套件內容:

suse:~ # rpm -q at
at-3.1.8-921.2

suse:~ # rpm -ql at
/etc/at.deny 可以將拒絕執行 at 程式的使用者名單設定在這裡。
/etc/init.d/atd 管理 at 排程服務的 script。
/usr/bin/at 編輯 at 排程的指令。
/usr/bin/atq 查詢 at 排程。如果是以 root 身分執行 atq 的話,會列出所有 user 的 at 排程。
/usr/bin/atrm 移除 at 排程。
/usr/bin/batch 另一個編輯 at 排程的指令,不過其所編輯的排程,只有在系統平均負載較低時才會執行。
/usr/sbin/atd 提供 at 排程服務的程式 (daemon)。
/usr/sbin/rcatd 連結至 /etc/init.d/atd 的符號連結檔。
/var/spool/atjobs 使用 at 指令所編輯好的排程,會寫入此目錄下的檔案之中。

 /usr/sbin/atd 是 at 排程執行的主程式,不過 SuSE 預設開機時是不啟動這個服務的,所以先把它啟動再說吧:

suse:~ # rcatd start
Starting service at daemon          done

 如想於下次開機時啟動 at 服務,那就設定一下囉:

suse:~ # chkconfig atd 35


8.2.2 設定 at 排程

 這裡主要是教大家使用 at 指令來編輯 at 排程,當然與 at 相關的檔案也要有所認識。at 學會了後,那另一個指令 batch 就更簡單了。

使用 at 指令建立 at 排程

 利用 at 指令所編輯的排程,只會在指定的時間執行那麼一次而已。

指令語法
at [-f file] TIME
at [-ldc] [jobs-number...]

 設定 at 排程很簡單,只要在指令後方輸入執行排程的時間,並按下 Enter 鍵後,就可以在 at 提示號下輸入您欲執行的程式。另外一種方式是先將 at 排程工作設定在檔案內,然後執行 "at -f file time" 即可。

參數說明

-l 列出 at 排程。"at -l" 同等於單一指令 "atq"。
-d 刪除 at 排程。其後需指定 at job number。"at -d" 同等於 "atrm"。
-c 列出 at 排程工作的內容。其後需指定 at job number。
-f 參數後需指定一檔案,此檔案內容就是 at 排程所要執行的工作。

 以下舉幾個 at 的時間格式給大家做參考:

範例一:於下午四點半執行 at 排程工作。
barry@suse:~> at 4:30pm
barry@suse:~> at 16:30
barry@suse:~> at 1630

範例二:從現在算起三分鐘後執行 at 排程。
barry@suse:~> at now +3minutes
# 也可以使用 weeks、days、hours、months 做時間單位。

範例三:於 2007 年十月二十日的 18:20 執行 at 排程。
barry@suse:~> at 18:20 10/20/2007
# 日期的格式也可以為 2007-10-20 或 20.10.2007。

範例四:從現在算起五天後的 16:00 執行排程。
barry@suse:~> at 4pm +5days

範例五:明天下午三點十五分執行排程。
barry@suse:~> at 15:15 tomorrow

範例六:兩週後的下午茶時間 (下午四點) 執行排程。
barry@suse:~> at teatime +2weeks


範例說明
barry@suse:~> at 1920
warning: commands will be executed using /bin/sh
at> cp -a ~/* /tmp/bckdir ← 編輯第一個 at 排程工作。
at> mail mary < ~/mailfile ← 編輯第二個 at 排程工作。
at> <EOT>
按下 Ctrl-D 來結束 at 排程的編寫,此時就會看到 <EOT> 這個字眼出現。
job 1 at 2007-02-25 19:20
#
顯示在這個時間會有一個 at job number 為 1 的 at 排程要執行。

# 現在再編輯另一個 at 排程:
barry@suse:~> at 1200 2007-09-22
warning: commands will be executed using /bin/sh
at> mail tina tom < ~/testfile
at> <EOT>
job 2 at 2007-09-22 12:00

# 接著可使用 at -l 或 atq 來列出 barry 自己的 at 排程執行時間:
barry@suse:~> at -l 
1 2007-02-25 19:20 a barry
2 2007-09-22 12:00 a barry

barry@suse:~> atq
1 2007-02-25 19:20 a barry
2 2007-09-22 12:00 a barry

# 如果想要瀏覽 job number 為 1 及 2 的 at 排程工作內容,請執行:
barry@suse:~> at -c 1 2

# 將排程工作事先寫在一個檔案裡,再配合 -f 參數使用:
tina@suse:~> vi /tmp/atfile
mkdir /tmp/tinadir
cp -a ~/* /tmp/tinadir


tina@suse:~> at -f /tmp/atfile 2330
warning: commands will be executed using /bin/sh
job 3 at 2007-02-25 23:30

# 現在請以 root 的身分執行 atq:
suse:~ # atq
1 2007-02-25 19:20 a barry
2 2007-09-22 12:00 a barry
3 2007-02-25 23:30 a tina
# 看到沒,管理者執行 atq 是可以看到所有使用者的 at 排程執行時間噢。

# 最後練習使用 at -d 或 atrm 來刪除 job number 為 1 的 at 排程:
barry@suse:~> at -d 1
barry@suse:~> atrm 1
# 以上兩種執行方式,與 "at -r 1" 是相同的。

at 相關檔案

  /var/spool/atjobs/*
    使用者所編輯好的 at 排程,會寫入 /var/spool/atjobs 目錄下的檔案裡。而當執行 "at -c job-number" 時,就是存取這些檔案的內容。
     
  /etc/at.deny、/etc/at.allow
    如果要限定一般使用者執行 at 去編輯排程,就必須使用這兩個檔案去做控管。
當 /etc/at.allow 檔案存在時,是會以這個檔案的設定為主,只有在 at.allow 不存在時,才會以 at.deny 為主。也就是說想拒絕少數使用者執行 at,可將這些使用者名單寫入 at.deny,但若只想允許少數使用者執行 at ,則把這些使用者名單設定在 at.allow 就行了。當兩個檔案同時存在時,會以 at.allow 的設定為主。

另外若只想讓 root 使用 at 來編排程,其他人全部都不能用,那麼在預設情形下我們有兩種方式可以達成這個目的:

  1. 移除 at.deny 檔案:
    suse:~ # rm -f /etc/at.deny

  2. 建立 at.allow 的空檔案:
    suse:~ # touch /etc/at.allow

使用 batch 指令建立 at 排程

 還有個可以執行 at 排程的指令叫 batch利用 batch 所建立的 at 排程,只有在系統平均負載較低時才會執行:

suse:~ # batch
warning: commands will be executed using /bin/sh
at> tar zcvf /backup/bck.taz /var /etc /home /srv
at> <EOT>
job 5 at 2007-02-28 14:03

 

copyright © 2006 by barry ( 柏青哥 )