你有没有遇到过这种情况——在服务器上写定时任务,心想「每天凌晨 3 点跑备份」,自信满满地写下 * 3 * * *,结果发现脚本每分钟都在跑,服务器差点被备份搞崩了?
或者更常见的:你在 crontab 里配了个每周一的报表任务,结果它周一到周日天天发邮件,老板被邮件轰炸到找你谈话。
这些坑我全踩过。Cron 表达式看起来简单——就 5 个字段嘛,分、时、日、月、周,能有多难?但正是这种看起来简单的东西,写错一个符号就让你怀疑人生。本文从语法到实战,把 Cron 讲透,再结合 navbox 的 Cron 表达式生成器 和 Cron 表达式解析器 给你一套完整的工作流。
一、Cron 表达式到底怎么读?
先上最基础的知识。一个标准的 Crontab 表达式有 5 个字段,顺序是固定的:
* * * * *
┬ ┬ ┬ ┬ ┬
│ │ │ │ └─ 星期 (0-7, 0和7都代表周日)
│ │ │ └────── 月份 (1-12)
│ │ └─────────── 日期 (1-31)
│ └─────────────── 小时 (0-23)
└─────────────────── 分钟 (0-59)
每个字段都可以用以下几种写法:
| 写法 | 含义 | 示例 |
|---|---|---|
* | 每(每个单位都执行) | * 在分钟字段 = 每分钟 |
*/N | 每隔 N 个单位 | */5 在分钟字段 = 每 5 分钟 |
N-M | 范围 | 9-18 在小时字段 = 早 9 点到晚 6 点 |
N,M,O | 列表 | 1,15 在日期字段 = 每月 1 号和 15 号 |
L | 最后(仅某些系统) | L 在日期字段 = 每月最后一天 |
记住了这些,大部分表达式你都能自己写出来。
最容易犯的错
新手最常犯的错误是把分钟字段写成 *。比如你想「每天凌晨 3 点执行」,写的是 * 3 * * *——这表示「每天 3 点的每分钟都执行」,也就是 3:00、3:01、3:02……直到 3:59,一共跑 60 次。正确的写法是 0 3 * * *(凌晨 3 点整执行一次)。
另一个经典错误是日期和星期同时设置。在标准 Crontab 中,日期字段和星期字段是**「或」的关系**——只要有一个匹配就会执行。所以 0 9 1 * 1 表示「每月 1 号 或 每周一早上 9 点执行」,而不是「每月 1 号且正好是周一才执行」。你是不是一直理解错了?
二、10 个最常用的 Cron 表达式
我把平时工作中用得最多的模式整理出来,方便你直接复制:
| 用途 | 表达式 | 说明 |
|---|---|---|
| 每分钟执行 | * * * * * | 调试用,生产环境慎用 |
| 每 5 分钟执行 | */5 * * * * | 监控检查、心跳上报 |
| 每 30 分钟执行 | */30 * * * * | 数据同步 |
| 每小时整点执行 | 0 * * * * | 日志切割、缓存刷新 |
| 每天凌晨 2 点执行 | 0 2 * * * | 备份、批量任务 |
| 每天早 9 点和晚 6 点 | 0 9,18 * * * | 上下班打卡提醒 |
| 每周一凌晨 3 点 | 0 3 * * 1 | 周报生成 |
| 每月 1 号凌晨 4 点 | 0 4 1 * * | 月报、对账 |
| 每季度首月 1 号 | 0 0 1 1,4,7,10 * | 季度汇总 |
| 工作日每 2 小时 | 0 */2 * * 1-5 | 工作时段巡检 |
这些模式覆盖了 90% 以上的使用场景。如果你需要更复杂的组合,直接用 Cron 表达式生成器 可视化点选就行,不用硬记语法。
三、用好两个在线工具,效率翻倍
navbox 上有两个 Cron 相关的工具,搭配使用效果最好。
3.1 Cron 表达式生成器——30 秒写出正确表达式
这个工具提供可视化界面,你把时间规则点选好,表达式自动生成。比如你想写「每周一到周五的上午 9:30 跑一次数据同步」:
- 选分钟:
30 - 选小时:
9 - 日期默认
* - 月份默认
* - 星期选
1-5(周一至周五)
工具自动生成 30 9 * * 1-5,复制粘贴到 crontab 里就行了。整个过程不超过 30 秒,比你翻手册回忆语法快得多。
特别适合的场景:
- 刚入行的开发,Cron 语法还不熟
- 表达式比较复杂,比如「每月最后一天」「每隔 3 小时」
- 要写多台服务器的批量配置,确保表达式一致
3.2 Cron 表达式解析器——写对没?一看便知
生成器负责「写」,解析器负责「验」。把写好的表达式粘贴到解析器里,它会列出接下来 5 次执行时间。这个功能在两种情况下特别救命:
场景 A:接手遗留系统
新公司入职,看到老代码里有几十个 Cron 表达式,注释要么没有要么过时了。把表达式一个一个丢进解析器,每个任务的执行时间一目了然——原来 0 0 * * 0 是每周日凌晨跑全量数据同步,不是每天跑。
场景 B:调试自己写的表达式
你把 0 2 * * *(每天凌晨 2 点)改成了 0 2 */2 * *(每隔两天凌晨 2 点),心里没底。用解析器一看:接下来执行时间是 6 月 2 日、6 月 4 日、6 月 6 日……间隔两天,完全正确。
四、实战:搭建一个完整的定时任务工作流
纸上谈兵够了,来一个真实的例子。假设你有一个电商网站,需要配置以下定时任务:
- 每分钟 检查订单支付超时
- 每 30 分钟 同步库存到第三方平台
- 每天凌晨 3 点 生成前一天的销售报表
- 每周一早上 8 点 发送周报邮件给团队
- 每月 1 号凌晨 4 点 做全量数据归档
按照传统方式,你得先查手册搞清楚每个表达式的写法,写完了还得等实际时间到了才知道对不对。用 navbox 的工具,流程变成这样:
第一步:用生成器写表达式
打开 Cron 表达式生成器,依次生成:
| 任务 | 表达式 | 生成操作 |
|---|---|---|
| 每分钟检查 | * * * * * | 全默认,分钟选 * |
| 每 30 分钟同步 | */30 * * * * | 分钟选 */30 |
| 每天 3 点报表 | 0 3 * * * | 分钟选 0,小时选 3 |
| 每周一 8 点邮件 | 0 8 * * 1 | 分钟 0,小时 8,星期选 1 |
| 每月 1 号 4 点归档 | 0 4 1 * * | 分钟 0,小时 4,日期选 1 |
第二步:用解析器验证
把生成的表达式一个个粘贴到 Cron 表达式解析器 里,确认执行时间符合预期。
尤其要注意「每周一 8 点」这个表达式——如果你写成了 0 8 * * 1 但发现解析器显示「每周一早上 8 点」,那是对的。但如果你本意是「每天 8 点」却不小心写成了 0 8 * * *,解析器会告诉你它每天都会执行。
第三步:写入 crontab
在服务器上执行 crontab -e,把表达式和命令逐行写入:
# 订单支付超时检查(每分钟)
* * * * * /usr/local/bin/check-order-timeout.sh
# 库存同步(每30分钟)
*/30 * * * * /usr/local/bin/sync-inventory.sh
# 销售报表(每天凌晨3点)
0 3 * * * /usr/local/bin/generate-sales-report.sh
# 周报邮件(每周一早上8点)
0 8 * * 1 /usr/local/bin/send-weekly-report.sh
# 数据归档(每月1号凌晨4点)
0 4 1 * * /usr/local/bin/archive-data.sh
第四步:日志验证
Cron 任务跑完后,检查 /var/log/cron 或 syslog 中的执行记录,确认每个任务都在正确的时间执行了。
五、避坑指南
最后分享几个我这些年踩过的坑,你遇到了可以直接查:
坑 1:服务器时区问题
云服务器默认时区可能是 UTC,你是北京时间(UTC+8),定时任务的执行时间跟你预期差了 8 个小时。部署前一定确认好时区:timedatectl 或 date 命令看一眼。
坑 2:环境变量缺失
Cron 执行环境和你 SSH 登录的环境不一样——Cron 默认不加载 .bashrc 或 .bash_profile,PATH 是精简版的。如果脚本里调用了 node、python3 等命令,建议在脚本开头写全路径,或者在 crontab 里先载入环境变量:
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
0 3 * * * /usr/local/bin/backup.sh
坑 3:输出日志被吃掉 Cron 默认不保存脚本的输出结果。如果脚本出错了,你连错误信息都看不到。最佳实践是把输出重定向到日志文件:
0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
这样日志会追加到文件里,排查问题时直接看日志就行了。
总结
Cron 表达式看似简单,但实际工作中踩坑的人络绎不绝。核心就三件事:记语法(5 个字段的顺序)、用工具(生成器写 + 解析器验)、看日志(确认执行正常)。
把你常用的几个表达式收藏好,遇到新需求时直接打开 Cron 表达式生成器 拖拽几下就完成了,不用每次都从头查手册。与其把脑力花在记语法上,不如把时间留给更有价值的事情。