Linux技巧:用cron和at調度作業 在 Linux 系統上,許多管理工作必須頻繁地定期執行。這些任務包括輪轉記錄檔以避免裝滿檔案系統、備份資料和連線時間伺服器來執行系統時間同步。上面提到的教程更詳細地介紹了這些管理工作。在本文中,學習 Linux 中提供的調度機制,包括 cron 和 anacron 設施以及 crontab 和 at 命令。即使系統常常關機,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.shIt is now 18:37:42 on Friday 建立 crontab使用 crontab 命令和 -e(表示 “edit”)選項建立 crontab。這會開啟 vi 編輯器,除非在 EDITOR 或 VISUAL 環境變數中指定了另一種編輯器。每個 crontab 條目包含六個欄位:分鐘小時日月星期由 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 在日誌中記錄輸出。但是,定向到 stdout 的輸出會通過電子郵件發送給使用者。清單 3 給出我們的命令樣本可能產生的輸出。清單 3. 通過電子郵件發送的 cron 輸出 From ian@lyrebird.raleigh.ibm.com Fri Jul 6 23:00:02 2007Date: Fri, 6 Jul 2007 23:00:01 -0400From: root@lyrebird.raleigh.ibm.com (Cron Daemon)To: ian@lyrebird.raleigh.ibm.comSubject: Cron <ian@lyrebird> /home/ian/mycrontest.shContent-Type: text/plain; charset=UTF-8Auto-Submitted: auto-generatedX-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 命令建立的 crontab 儲存在 /etc/spool/cron 下面的一個子目錄中,這個子目錄與建立 crontab 的使用者同名,所以上面的 crontab 儲存在 /etc/spool/cron/ian 中。因此,與 passwd 命令一樣,crontab 命令是一個用根許可權啟動並執行 suid 程式。/etc/crontab除了 /var/spool/cron 中的使用者 crontab 檔案之外,cron 還會檢查 /etc/crontab 檔案和 /etc/cron.d 目錄中的檔案。在這些系統 crontab 中,在第五個時間欄位(星期)和命令之間增加了一個欄位。這個欄位指定哪個使用者應該運行這個命令,一般情況下是根使用者。清單 4 給出一個 /etc/crontab 檔案樣本。 清單 4. /etc/crontab SHELL=/bin/bashPATH=/sbin:/bin:/usr/sbin:/usr/binMAILTO=rootHOME=/ # run-parts01 * * * * root run-parts /etc/cron.hourly02 4 * * * root run-parts /etc/cron.daily22 4 * * 0 root run-parts /etc/cron.weekly42 4 1 * * root run-parts /etc/cron.monthly 在這個樣本中,真正的工作由 run-parts 命令執行,它運行 /etc/cron.hourly、/etc/cron.daily 等目錄中的指令碼;/etc/crontab 僅僅控制執行作業的時間。注意,這裡的所有命令都作為根使用者運行。還要注意,crontab 可以包含 shell 變數賦值,這些賦值會在運行命令之前執行。anacroncron 適合那些連續啟動並執行系統。對於那些常常不開機的系統,比如筆記本電腦,可以使用另一個公用程式 anacron(表示 “anachronistic cron”)調度每日、每周或每月執行的作業。anacron 不處理每小時執行的作業。anacron 在 /var/spool/anacron 中保留時間戳檔案,記錄作業啟動並執行時間。當 anacron 運行時,它檢查自作業上一次運行以來是否已經經過了所需的天數,如果需要,就運行作業。anacron 的作業表格儲存體在 /etc/anacrontab 中,檔案格式與 /etc/crontab 略有不同。與 /etc/crontab 一樣,/etc/anacrontab 可以包含環境設定。每個作業有四個欄位:周期延遲作業標識符命令周期是天數,但是可以指定為 @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:25Sat Jul 7 10:25:00 2007 job 5 at Sat Jul 7 10:25:00 2007 清單 6. 來自 at 的作業輸出 From ian@lyrebird.raleigh.ibm.com Sat Jul 7 10:25:00 2007Date: Sat, 7 Jul 2007 10:25:00 -0400From: Ian Shields <ian@lyrebird.raleigh.ibm.com>Subject: Output from your job 5To: ian@lyrebird.raleigh.ibm.com 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 tomorrowjob 14 at Sun Jul 8 22:00:00 2007[ian@lyrebird ~]$ at -f mycrontest.sh 2:00 tuesdayjob 15 at Tue Jul 10 02:00:00 2007[ian@lyrebird ~]$ at -f mycrontest.sh 2:00 july 11job 16 at Wed Jul 11 02:00:00 2007[ian@lyrebird ~]$ at -f mycrontest.sh 2:00 next weekjob 17 at Sat Jul 14 02:00:00 2007 管理調度的作業列出調度的作業可以管理 cron 和 at 作業。使用 crontab 命令和 -l 選項列出 crontab,使用 atq 命令顯示用 at 命令排入佇列中的作業,見清單 8。 清單 8. 顯示調度的作業 [ian@lyrebird ~]$ crontab -l0,20,40 22-23 * 7 fri-sat /home/ian/mycrontest.sh[ian@lyrebird ~]$ atq16 Wed Jul 11 02:00:00 2007 a ian17 Sat Jul 14 02:00:00 2007 a ian14 Sun Jul 8 22:00:00 2007 a ian15 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 0umask 2HOSTNAME=lyrebird.raleigh.ibm.com; export HOSTNAMESHELL=/bin/bash; export SHELLHISTSIZE=1000; export HISTSIZESSH_CLIENT=9.67.219.151\ 3210\ 22; export SSH_CLIENTSSH_TTY=/dev/pts/5; export SSH_TTYUSER=ian; export USER ...HOME=/home/ian; export HOMELOGNAME=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)。 刪除調度的作業可以使用 cron 命令和 -r 選項刪除所有調度的 cron 作業,見清單 10。 清單 10. 顯示並刪除 cron 作業 [ian@lyrebird ~]$ crontab -l0,20,40 22-23 * 7 fri-sat /home/ian/mycrontest.sh[ian@lyrebird ~]$ crontab -r[ian@lyrebird ~]$ crontab -lno crontab for ian 要刪除系統 cron 或 anacron 作業,應該編輯 /etc/crontab、/etc/anacrontab 或者編輯或刪除 /etc/cron.d 目錄中的檔案。可以使用 atrm 命令加作業號刪除用 at 命令調度的一個或多個作業。多個作業應該用空白分隔。清單 11 給出一個樣本。 清單 11. 用 atq 和 atrm 顯示並刪除作業 [ian@lyrebird ~]$ atq16 Wed Jul 11 02:00:00 2007 a ian17 Sat Jul 14 02:00:00 2007 a ian14 Sun Jul 8 22:00:00 2007 a ian15 Tue Jul 10 02:00:00 2007 a ian[ian@lyrebird ~]$ atrm 16 14 15[ian@lyrebird ~]$ atq17 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 設施起相似的作用。