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 在线解析 / 生成(输入表达式直接出下次执行时间,也支持反向生成)

上线前的检查清单

  1. crontab -l 确认写进去了,用户别写错(root 和 www 的任务完全隔离)
  2. 手动跑一次命令,确认退出码是 0
  3. /var/log/cron(CentOS)或 journalctl -u cron(Ubuntu)确认真被触发
  4. 涉及写文件的,确认运行用户有权限
  5. 改完先设成一个最近的时间点验证,别等到凌晨 2 点才发现没跑

相关工具都在 997 工具箱crontab 解析Linux 命令速查docker 命令速查,纯前端,数据不上传。

posted @ 2026-09-19 01:58  k8sdoc  阅读(4)  评论(0)    收藏  举报