在 crontab 的指令設定中,百分比符號(%)有特殊含義:它會被解釋為換行字元(newline)。如果你的指令中有 %(例如 date "+%Y-%m-%d"),必須用反斜線跳脫,否則 cron 會靜默地執行錯誤,甚至不執行任何動作。
問題症狀
設定了 crontab 但指令沒有執行,查看 /var/log/syslog 看到類似這樣的截斷訊息:
1
|
Nov 1 01:00:01 raspberrypi /USR/SBIN/CRON[1361]: (debian-transmission) CMD (mkdir /mnt/extHDD/Download/Mikata/`date "+)
|
可以看到 date "+%Y-%m-%d" 被截斷在 % 之前,這就是 % 被解讀為換行的結果。
解決方式:跳脫百分比符號
在 crontab 中,所有的 % 都必須改寫為 \%:
1
2
3
4
5
|
# 錯誤的寫法(date 指令不會正確執行)
0 1 * * * mkdir /data/backup/`date "+%Y-%m-%d"`
# 正確的寫法(所有 % 都要跳脫)
0 1 * * * mkdir /data/backup/`date "+\%Y-\%m-\%d"`
|
另一種常見的解決方式是將指令移到獨立的 shell 腳本中:
1
2
3
|
# /home/pi/backup.sh
#!/bin/bash
mkdir /data/backup/$(date "+%Y-%m-%d")
|
然後在 crontab 中呼叫腳本:
1
|
0 1 * * * /home/pi/backup.sh
|
如何查看 cron 執行日誌
Debian/Ubuntu/Raspberry Pi
1
2
3
4
5
|
# 搜尋 syslog 中的 cron 記錄
grep CRON /var/log/syslog
# 即時監看 cron 日誌
tail -f /var/log/syslog | grep CRON
|
CentOS/RHEL
1
2
3
|
# cron 有獨立的日誌檔
cat /var/log/cron
tail -f /var/log/cron
|
systemd 系統(較新的 Linux 發行版)
1
2
3
4
5
6
|
# 使用 journalctl 查看
journalctl -u cron
journalctl -u crond
# 即時監看
journalctl -u cron -f
|
Crontab 常見的其他陷阱
1. 環境變數問題
cron 執行時的環境變數與使用者 shell 不同,PATH 通常只有 /usr/bin:/bin,因此執行自訂工具時需要使用完整路徑:
1
2
3
4
5
6
7
8
9
|
# 錯誤:node 可能找不到
0 * * * * node /home/pi/app/index.js
# 正確:使用完整路徑
0 * * * * /usr/local/bin/node /home/pi/app/index.js
# 或在 crontab 頂部設定 PATH
PATH=/usr/local/bin:/usr/bin:/bin
0 * * * * node /home/pi/app/index.js
|
2. 工作目錄問題
cron 預設的工作目錄是使用者的 home 目錄,若腳本依賴相對路徑,需要先 cd:
1
|
0 * * * * cd /home/pi/myapp && npm start
|
3. 輸出要導向
cron 的 stdout/stderr 預設會以 email 方式通知,若要儲存到檔案:
1
|
0 * * * * /home/pi/backup.sh >> /var/log/backup.log 2>&1
|
若不想要任何輸出(靜默執行):
1
|
0 * * * * /home/pi/backup.sh > /dev/null 2>&1
|
4. Crontab 時間格式速查
1
2
3
4
5
6
7
|
* * * * * 指令
│ │ │ │ │
│ │ │ │ └── 星期幾 (0-7, 0和7都是週日)
│ │ │ └──── 月份 (1-12)
│ │ └────── 日期 (1-31)
│ └──────── 小時 (0-23)
└────────── 分鐘 (0-59)
|
1
2
3
4
5
6
7
8
|
# 每天凌晨 1 點執行
0 1 * * * /home/pi/daily.sh
# 每週一上午 9 點執行
0 9 * * 1 /home/pi/weekly.sh
# 每 5 分鐘執行一次
*/5 * * * * /home/pi/check.sh
|
參考資料