Crontab 是 Linux 系統級定時任務調度器,廣泛用於數據庫備份、日誌清理、報表生成、緩存預熱等自動化運維場景。本文系統總結配置文件位置、命令語法、時間表達式、常見坑點(環境變量、路徑、重複執行)及最佳實踐。
| 路徑 | 用途 |
|---|---|
/etc/crontab | 系統級任務(需指定運行用戶),由 cron 守護進程直接讀取 |
/var/spool/cron/ | 用戶級任務目錄,每用戶一個文件(如 /var/spool/cron/root) |
/etc/cron.d/ | 應用安裝包投放任務片段的目錄(同 /etc/crontab 格式) |
/etc/cron.allow / /etc/cron.deny | 控制用戶是否允許使用 crontab 命令(allow 優先,不存在則 deny 生效) |
/etc/cron.hourly/daily/weekly/monthly/ | 系統周期性腳本目錄,由 run-parts 通過 /etc/crontab 觸發 |
crontab -l # 查看當前用戶任務列表 crontab -e # 編輯當前用戶任務(打開編輯器,保存後自動生效) crontab -r # 刪除當前用戶所有任務(慎用!) crontab -u user -l # root 查看指定用戶任務 crontab /path/file # 從文件導入任務覆蓋當前
* * * * * command-to-execute - - - - - | | | | └─ 星期 (0-7) (0或7=星期日) | | | └──── 月份 (1-12) | | └────── 日期 (1-31) | └──────── 小時 (0-23) └────────── 分鐘 (0-59)
*:任意值(每分鐘/每小時...)*/n:每 n 分鐘/小時...(如 */5 * * * * 每 5 分鐘)a-b:範圍(如 9-18 表示 9 點到 18 點)a,b,c:離散列表(如 1,15,30 表示 1、15、30 分)# 每天 12:12 執行備份腳本 12 12 * * * /home/backup/daily.sh >> /home/backup/daily.log 2>&1 # 每 2 分鐘檢查服務狀態 */2 * * * * /usr/local/bin/check_service.sh # 工作日 23:00 執行報表生成 0 23 * * 1-5 /home/reports/generate.sh # 每周日 19:00 發送郵件摘要 0 19 * * 0 mail -s "Weekly Report" admin@example.com < /tmp/weekly.txt # 系統啟動後 5 分鐘執行(需 @reboot 支援) @reboot sleep 300 && /home/scripts/startup.sh
/dev/null 2>&1 深度解析# 文件描述符:0=stdin, 1=stdout, 2=stderr # > file : 1> file (標準輸出重定向到文件) # 2> file : 錯誤輸出重定向到文件 # 2>&1 : 錯誤輸出重定向到 標準輸出(即文件描述符 1 指向的地方) # &> file : 1>file 2>&1 的簡寫 # 完整寫法:標準輸出和錯誤輸出都寫入日誌文件 * * * * * /path/script.sh >> /var/log/script.log 2>&1 # 完全丟棄輸出(靜默運行) * * * * * /path/script.sh > /dev/null 2>&1 # 僅保留錯誤日誌 * * * * * /path/script.sh > /dev/null 2>> /var/log/script_error.log
注意:2>1(缺少 &)會被理解為「錯誤輸出重定向到名為 1 的文件」,而非標準輸出。
Cron 運行環境極簡(無 PATH、HOME、LANG 等)。腳本內必須顯式聲明:
#!/bin/bash # 腳本頭部聲明 export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin export LANG=en_US.UTF-8 # 或 source /etc/profile
/home/user/scripts/backup.sh/usr/bin/php、/usr/bin/mysqldump、/bin/date/data/backup/任務執行時間超過調度間隔會導致併發,造成資源爭搶、數據不一致。
# 方法一:flock 文件鎖(推薦,自動釋放)
* * * * * flock -xn /tmp/myjob.lock -c '/home/scripts/myjob.sh'
# 方法二:進程檢查(適用於無 flock 環境)
* * * * * pgrep -f 'myjob.sh' > /dev/null || /home/scripts/myjob.sh
# 方法三:腳本內部 PID 文件鎖
#!/bin/bash
LOCK="/tmp/myjob.pid"
if [ -f $LOCK ] && kill -0 $(cat $LOCK) 2>/dev/null; then
echo "Already running" ; exit 1
fi
echo $$ > $LOCK
trap "rm -f $LOCK" EXIT
# ... 業務邏輯 ...
systemctl status cron 或 systemctl status crondgrep CRON /var/log/syslog(Debian/Ubuntu)或 /var/log/cron(CentOS/RHEL)/home/scripts/backup.sh 確認無語法錯誤、權限問題。MAILTO="" 禁用,或 MAILTO="admin@example.com" 指定接收郵箱(需配置 postfix/sendmail)。systemd Timer 提供更精確的時間控制、依賴管理、日誌整合、隨機延遲(RandomizedDelaySec)等優勢。
# /etc/systemd/system/backup.timer [Unit] Description=Daily Backup Timer [Timer] OnCalendar=daily Persistent=true RandomizedDelaySec=30m [Install] WantedBy=timers.target # /etc/systemd/system/backup.service [Unit] Description=Daily Backup Service [Service] Type=oneshot ExecStart=/home/backup/daily.sh # 啟用 systemctl daemon-reload systemctl enable --now backup.timer