Cron 表达式写错就是生产事故:8 个真实例子 + 5 个必踩的坑
先记住格式
标准 Linux crontab 是 5 段(分钟 小时 日 月 星期),Spring/Quartz 是 6 段(多了秒):
# Linux crontab:5 段
* * * * * command
│ │ │ │ │
│ │ │ │ └── 星期 (0-7, 0和7都是周日)
│ │ │ └───── 月 (1-12)
│ │ └──────── 日 (1-31)
│ └─────────── 小时 (0-23)
└────────────── 分钟 (0-59)
注意:Linux 的 crontab 没有「秒」这一位。从 Spring 那边抄一个 0 */5 * * * * 过来会直接报错(多了 1 段)。
8 个能直接抄的例子
0 2 * * * # 每天凌晨 2 点
30 3 * * 1 # 每周一 3:30
0 */2 * * * # 每 2 小时整点
*/10 * * * * # 每 10 分钟
0 9-18 * * 1-5 # 工作日 9 点到 18 点,每天整点
0 0 1 * * # 每月 1 号 0 点
0 0 1,15 * * # 每月 1 号和 15 号
0 4 1 * * # 每月 1 号 4 点(月度报表常用)
看着简单,但下面这 5 个坑我基本都见过线上出事。
坑 1:0/5 和 */5 不一样(其实一样,但 5 完全不是)
*/5 * * * *= 每 5 分钟(0,5,10…55)✅5 * * * *= 每小时的第 5 分钟(1:05、2:05…)❌ 很多人写错成这个0/5 * * * *= 从 0 开始每 5 分钟,和*/5等价
坑 2:日 和 星期 同时指定,是「或」不是「且」
0 0 13 * 5
不是「13 号且是周五」,而是「13 号 或 每个周五」都会执行。两个字段只要有一个匹配就跑,这点非常反直觉。要限制就只留一个,另一个写 *。
坑 3:环境变量几乎不存在
crontab 的执行环境里 PATH 只有 /usr/bin:/bin。所以:
# 错:node / java / python3 经常找不到
* * * * * node /opt/app/task.js
# 对:写绝对路径,或在文件顶部声明 PATH
PATH=/usr/local/bin:/usr/bin:/bin
* * * * * /usr/local/bin/node /opt/app/task.js
调试技巧:先跑 env -i /bin/bash -c 'your command' 复现 cron 的空环境。
坑 4:没重定向输出,磁盘被日志撑爆
cron 的输出会发邮件,邮件服务没配就堆在 /var/spool/mail。正确写法:
*/5 * * * * /opt/app/sync.sh >> /var/log/sync.log 2>&1
再配合 logrotate,否则半年后你会收到磁盘告警。
坑 5:任务重叠执行
任务跑了 10 分钟,但每 5 分钟触发一次,就会有两个实例并发跑。加个锁:
*/5 * * * * flock -n /tmp/sync.lock -c '/opt/app/sync.sh >> /var/log/sync.log 2>&1'
flock -n 拿不到锁就直接退出,不会堆积。
写完先验证一遍
改完 crontab 别直接上线,先把表达式丢进解析器看人类可读的描述和接下来几次执行时间,确认和自己想的一致:
👉 crontab 在线解析 / 生成(输入表达式直接出下次执行时间,也支持反向生成)
上线前的检查清单
crontab -l确认写进去了,用户别写错(root 和 www 的任务完全隔离)- 手动跑一次命令,确认退出码是 0
- 看
/var/log/cron(CentOS)或journalctl -u cron(Ubuntu)确认真被触发 - 涉及写文件的,确认运行用户有权限
- 改完先设成一个最近的时间点验证,别等到凌晨 2 点才发现没跑
相关工具都在 997 工具箱:crontab 解析、Linux 命令速查、docker 命令速查,纯前端,数据不上传。
浙公网安备 33010602011771号