Linux 技巧: 用 cron 和 at 調度作業

系統管理員需要在系統負載低的午夜運行作業,或者需要每天或每月運行作業,同時又不願意犧牲睡眠時間或假期。調度任務的其他原因包括自動執行日常任務或者確保每次都以相同的方式處理任務。本文幫助您使用 cronat 功能調度作業定期運行或在指定的時間運行一次。
Linux® 和 UNIX® 系統允許調度任務在以後執行一次,或者重複運行。本文是從 developerWorks 教程 “LPI 102 考試準備:管理任務” 摘錄的,講解如何調度作業定期運行,或在指定的時間運行一次。
在 Linux 系統上,許多管理任務必須頻繁地定期執行。這些任務包括輪轉日誌文件以避免裝滿文件系統、備份數據和連接時間服務器來執行系統時間同步。上面提到的教程更詳細地介紹了這些管理任務。在本文中,學習 Linux 中提供的調度機制,包括 cronanacron 設施以及 crontabat 命令。即使系統常常關機,anacron 也可以幫助調度作業。
以一定的時間間隔運行作業需要使用 cron 設施進行管理,它由 crond 守護進程和一組表(描述執行哪些操作和採用什麼樣的頻率)組成。這個守護進程每分鐘喚醒一次,並通過檢查 crontab 判斷需要做什麼。用戶使用 crontab 命令管理 crontab。crond 守護進程常常是在系統啓動時由 init 進程啓動的。
爲了簡單,假設希望定期運行清單 1 所示的命令。這個命令實際上只報告日期和時間,其他什麼事都不做,但是它可以說明如何使用 crontab 設置 cron 作業,而且還可以通過輸出看到作業運行的時間。設置 crontab 條目需要一個包含轉義的 shell 元字符的字符串,所以適合於簡單的命令和參數。在這個示例中,將從腳本 /home/ian/mycrontab.sh 運行 echo 命令,這個腳本不需要參數。 這可以減少處理轉義字符的工作。

清單 1. 一個簡單的命令示例
                
[ian@lyrebird ~]$ cat mycrontest.sh
#!/bin/bash
 echo "It is now $(date +%T) on $(date +%A)"
[ian@lyrebird ~]$ ./mycrontest.sh
It is now 18:37:42 on Friday

使用 crontab 命令和 -e(表示 “edit”)選項創建 crontab。這會打開 vi 編輯器,除非在 EDITOR 或 VISUAL 環境變量中指定了另一種編輯器。
每個 crontab 條目包含六個字段:
  1. 分鐘
  2. 小時
  3. 星期
  4. sh 執行的字符串
分鐘和小時的範圍分別是 0-59 和 0-12,日和月的範圍分別是 1-31 和 1-12。星期的範圍是 0-6,0 表示星期日。星期也可以指定爲 sun、mon、tue 等等。第 6 個字段包含前 5 個字段之後的所有內容,它是要傳遞給 sh 的字符串。百分號(%)將轉換爲空行,所以如果要使用 % 或其他任何特殊字符,就要在前面加上反斜線(\)。第一個 % 之前的一行傳遞給 shell,這個 % 之後的所有行都作爲標準輸入傳遞。
各個與時間相關的字段可以指定一個單獨的值、值的範圍(比如 0-10 或 sun-wed)或者以逗號分隔的單獨值和範圍列表。清單 2 給出一個 crontab 條目示例。

清單 2. 一個簡單的 crontab 示例
                
0,20,40 22-23 * 7 fri-sat /home/ian/mycrontest.sh

在這個示例中,我們的命令在 7 月的每個星期五和星期六晚上 10 點到午夜之間的第 0、20、40 分鐘(每 20 分鐘)執行。關於指定時間的其他方式的細節,參見 crontab(5) 的手冊頁。
您可能想知道對來自命令的輸出會如何處理。爲使用 cron 而設計的大多數命令會使用 syslog 在日誌中記錄輸出(參見教程 “LPI 102 考試準備:管理任務” 中的討論)。但是,定向到 stdout 的輸出會通過電子郵件發送給用戶。清單 3 給出我們的命令示例可能產生的輸出。

清單 3. 通過電子郵件發送的 cron 輸出
                
From [email][email protected][/email]  Fri Jul  6 23:00:02 2007
Date: Fri, 6 Jul 2007 23:00:01 -0400
From: [email][email protected][/email] (Cron Daemon)
To: [email][email protected][/email]
Subject: Cron <ian@lyrebird> /home/ian/mycrontest.sh
Content-Type: text/plain; charset=UTF-8
Auto-Submitted: auto-generated
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/home/ian>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=ian>
X-Cron-Env: <USER=ian>
It is now 23:00:01 on Friday

crontab 命令創建的 crontab 存儲在 /etc/spool/cron 下面的一個子目錄中,這個子目錄與創建 crontab 的用戶同名,所以上面的 crontab 存儲在 /etc/spool/cron/ian 中。因此,與 passwd 命令一樣,crontab 命令是一個用根權限運行的 suid 程序。
除了 /var/spool/cron 中的用戶 crontab 文件之外,cron 還會檢查 /etc/crontab 文件和 /etc/cron.d 目錄中的文件。在這些系統 crontab 中,在第五個時間字段(星期)和命令之間增加了一個字段。這個字段指定哪個用戶應該運行這個命令,一般情況下是根用戶。清單 4 給出一個 /etc/crontab 文件示例。

清單 4. /etc/crontab
                
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/
# run-parts
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly
      

在這個示例中,真正的工作由 run-parts 命令執行,它運行 /etc/cron.hourly、/etc/cron.daily 等目錄中的腳本;/etc/crontab 僅僅控制執行作業的時間。注意,這裏的所有命令都作爲根用戶運行。還要注意,crontab 可以包含 shell 變量賦值,這些賦值會在運行命令之前執行。
cron 適合那些連續運行的系統。對於那些常常不開機的系統,比如筆記本計算機,可以使用另一個實用程序 anacron(表示 “anachronistic cron”)調度每日、每週或每月執行的作業。anacron 不處理每小時執行的作業。
anacron 在 /var/spool/anacron 中保留時間戳文件,記錄作業運行的時間。當 anacron 運行時,它檢查自作業上一次運行以來是否已經經過了所需的天數,如果需要,就運行作業。anacron 的作業表存儲在 /etc/anacrontab 中,文件格式與 /etc/crontab 略有不同。與 /etc/crontab 一樣,/etc/anacrontab 可以包含環境設置。每個作業有四個字段:
  1. 週期
  2. 延遲
  3. 作業標識符
  4. 命令
週期是天數,但是可以指定爲 @monthly,這確保作業每個月只運行一次(無論這個月中有多少天)。延遲是在作業符合運行條件之後,到實際啓動它之前等待的分鐘數。可以使用這個設置防止在系統啓動時集中執行作業。作業標識符可以包含除了斜線(/)之外的所有非空白字符。
/etc/crontab 和 /etc/anacrontab 都通過直接編輯進行更新。不使用 crontab 命令更新這些文件或 /etc/cron.d 目錄中的文件。
有時候,需要只運行作業一次而不是定期運行。爲此,應該使用 at 命令。要運行的命令是從 -f 選項指定的文件讀取的,如果沒有使用 -f,那麼從 stdin 讀取。-m 選項向用戶發送郵件,即使命令沒有 stdout。-v 選項顯示運行作業的時間。這個時間也顯示在輸出中。
清單 5 給出一個運行 mycrontest.sh 腳本的示例。清單 6 顯示在運行作業之後通過郵件發送給用戶的輸出。注意,這裏的輸出比對應的 cron 作業輸出要簡單一些。

清單 5. 使用 at 命令
                
[ian@lyrebird ~]$ at -f mycrontest.sh -v 10:25
Sat Jul  7 10:25:00 2007
job 5 at Sat Jul  7 10:25:00 2007


清單 6. 來自 at 的作業輸出
                
From [email][email protected][/email]  Sat Jul  7 10:25:00 2007
Date: Sat, 7 Jul 2007 10:25:00 -0400
From: Ian Shields <[email][email protected][/email]>
Subject: Output from your job        5
To: [email][email protected][/email]
It is now 10:25:00 on Saturday

時間的設置可以非常複雜。清單 7 給出幾個示例。參見 at 的手冊頁、/usr/share/doc/at/timespec 文件或 /usr/share/doc/at-3.1.10/timespec 這樣的文件(這個示例中的 3.1.10 是 at 包的版本號)。

清單 7. at 命令使用的時間值
                
[ian@lyrebird ~]$ at -f mycrontest.sh  10pm tomorrow
job 14 at Sun Jul  8 22:00:00 2007
[ian@lyrebird ~]$ at -f mycrontest.sh 2:00 tuesday
job 15 at Tue Jul 10 02:00:00 2007
[ian@lyrebird ~]$ at -f mycrontest.sh 2:00 july 11
job 16 at Wed Jul 11 02:00:00 2007
[ian@lyrebird ~]$ at -f mycrontest.sh 2:00 next week
job 17 at Sat Jul 14 02:00:00 2007

at 命令還有一個 -q 選項。隨着隊列的增長,作業的 nice 值也會增長。 還有一個 batch 命令,它與 at 命令相似,但是作業只在系統負載足夠低時運行。這些特性的細節參見手冊頁。





可以管理 cron 和 at 作業。使用 crontab 命令和 -l 選項列出 crontab,使用 atq 命令顯示用 at 命令加入隊列中的作業,見清單 8。

清單 8. 顯示調度的作業
                
[ian@lyrebird ~]$ crontab -l
0,20,40 22-23 * 7 fri-sat /home/ian/mycrontest.sh
[ian@lyrebird ~]$ atq
16      Wed Jul 11 02:00:00 2007 a ian
17      Sat Jul 14 02:00:00 2007 a ian
14      Sun Jul  8 22:00:00 2007 a ian
15      Tue Jul 10 02:00:00 2007 a ian

如果希望查看 at 調度執行的實際命令,那麼可以使用 at 命令並加上 -c 選項和作業號。您會注意到,在發出 at 命令時生效的大多數環境設置會隨調度的作業一起保存。清單 9 給出清單 7 和清單 8 中作業 15 的部分輸出。

清單 9. 使用 at -c 並加上作業號
                
#!/bin/sh
# atrun uid=500 gid=500
# mail ian 0
umask 2
HOSTNAME=lyrebird.raleigh.ibm.com; export HOSTNAME
SHELL=/bin/bash; export SHELL
HISTSIZE=1000; export HISTSIZE
SSH_CLIENT=9.67.219.151\ 3210\ 22; export SSH_CLIENT
SSH_TTY=/dev/pts/5; export SSH_TTY
USER=ian; export USER
 ...
HOME=/home/ian; export HOME
LOGNAME=ian; export LOGNAME
 ...
cd /home/ian || {
         echo 'Execution directory inaccessible' >&2
         exit 1
}
${SHELL:-/bin/sh} << `(dd if=/dev/urandom count=200 bs=1 \
   2>/dev/null|LC_ALL=C tr -d -c '[:alnum:]')`
#!/bin/bash
 echo "It is now $(date +%T) on $(date +%A)"

注意,我們腳本文件的內容已經複製在一個 here-document 中,這個 here-document 將由 SHELL 變量指定的 shell 執行(如果沒有設置 SHELL 變量,就使用 /bin/sh)。關於 here-document 的信息參見教程 “LPI 101 考試準備,主題 103:GNU 和 UNIX 命令”。
可以使用 cron 命令和 -r 選項刪除所有調度的 cron 作業,見清單 10。

清單 10. 顯示並刪除 cron 作業
                
[ian@lyrebird ~]$ crontab -l
0,20,40 22-23 * 7 fri-sat /home/ian/mycrontest.sh
[ian@lyrebird ~]$ crontab -r
[ian@lyrebird ~]$ crontab -l
no crontab for ian

要刪除系統 cron 或 anacron 作業,應該編輯 /etc/crontab、/etc/anacrontab 或者編輯或刪除 /etc/cron.d 目錄中的文件。
可以使用 atrm 命令加作業號刪除用 at 命令調度的一個或多個作業。多個作業應該用空白分隔。清單 11 給出一個示例。

清單 11. 用 atq 和 atrm 顯示並刪除作業
                
[ian@lyrebird ~]$ atq
16      Wed Jul 11 02:00:00 2007 a ian
17      Sat Jul 14 02:00:00 2007 a ian
14      Sun Jul  8 22:00:00 2007 a ian
15      Tue Jul 10 02:00:00 2007 a ian
[ian@lyrebird ~]$ atrm 16 14 15
[ian@lyrebird ~]$ atq
17      Sat Jul 14 02:00:00 2007 a ian
 
如果文件 /etc/cron.allow 存在,那麼非根用戶必須在其中列出,才能使用 crontab 和 cron 設施。如果 /etc/cron.allow 不存在,但是 /etc/cron.deny 存在,那麼其中列出的非根用戶不能使用 crontab 或 cron 設施。如果這兩個文件都不存在,那麼只允許超級用戶使用這個命令。空的 /etc/cron.deny 文件允許所有用戶使用 cron 設施,這是默認情況。
/etc/at.allow 和 /etc/at.deny 文件對 at 設施起相似的作用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章