Contents

Crontab指令打百分比需要跳脫符號

在 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

參考資料