Cron 表达式详解:从入门到精通
全面解析 Cron 表达式的语法结构、特殊字符含义及常用示例。无论你是运维还是开发人员,都能通过本文掌握定时任务的配置技巧。
在 Linux 系统管理和后端开发中,Cron 是一个无处不在的名字。它是类 Unix 系统下的定时任务调度器,用于在预定的时间自动执行命令或脚本。无论是每天备份数据库、每周发送报表,还是每分钟检查服务状态,Cron 都是最得力的助手。
而配置 Cron 任务的核心,就是编写 Cron 表达式。对于初学者来说,这一串由星号、斜杠和数字组成的字符可能看起来像天书。本文将带你深入理解 Cron 表达式,让你能够轻松驾驭各种定时任务。
如果你需要快速生成或校验 Cron 表达式,推荐使用我们的 Cron 表达式生成器,它可以可视化地帮助你构建正确的表达式。
1. 什么是 Cron 表达式?
Cron 表达式(更准确地说,是“类 Cron”时间表达式)是一个由多个字段组成的字符串,每个字段代表时间的一个维度。不同实现的字段数量与语义可能并不完全相同:Linux 的 crontab 固定为 5 个字段,而 Quartz / Spring 等调度器通常包含秒(6 或 7 个字段)并支持更多特殊字符。本文会区分说明两者差异,避免混淆。
标准的 Linux Crontab 使用 5 个字段,格式如下:
* * * * *
| | | | |
| | | | +----- 星期 (0 - 7) (0 和 7 都表示星期日)
| | | +------- 月份 (1 - 12)
| | +--------- 日期 (1 - 31)
| +----------- 小时 (0 - 23)
+------------- 分钟 (0 - 59)
2. 字段详解(Linux Crontab:5 字段)
| 字段 | 允许的值 | 允许的特殊字符 |
|---|---|---|
| 分钟 | 0-59 | * , - / |
| 小时 | 0-23 | * , - / |
| 日期(Day of Month) | 1-31 | * , - / |
| 月份 | 1-12(部分实现支持 JAN-DEC) | * , - / |
| 星期(Day of Week) | 0-7(部分实现支持 SUN-SAT) | * , - / |
注意:
- 星期字段中,
0和7通常都代表星期日。- 标准 Linux Cron 不支持秒级调度(最小粒度为分钟)。如果需要秒级,通常需要结合脚本循环或使用更高级的调度器。
- 在 Linux Cron 中,“日期”和“星期”字段如果都写了非
*的限制条件,匹配关系通常是“或”(任一满足就会触发),并不是很多人以为的“且”。实践中更推荐只限制其中一个字段,另一个保持*。
3. 字段详解(Quartz / Spring 等扩展:含秒)
在 Quartz(以及一些类 Cron 实现)中,表达式通常包含 6 或 7 个字段(含秒)。格式如下:
秒 分 时 日期 月份 星期 年份 (可选)
| | | | | | |
0-59 0-59 0-23 1-31 1-12 1-7 1970-2099
重要区别:星期字段
- Linux Crontab: 0-7 (0 和 7 均为周日)
- Quartz: 1-7 (1 为周日,2 为周一,以此类推) 请务必确认你的系统使用哪种标准!
这类表达式支持更多特殊字符(如 ?、L、W、#),与 Linux crontab 不完全兼容,复制粘贴时要特别小心。
4. 特殊字符含义
4.1 Linux Cron 常用特殊字符
*(星号):代表”每”。例如,在分钟字段使用*,表示每分钟。,(逗号):代表”枚举”。例如,5,10,15表示在第 5、10、15 分钟执行。-(连字符):代表”范围”。例如,10-12表示在 10 点、11 点、12 点执行。/(斜杠):代表”步长”(间隔)。例如,*/5表示每隔 5 个单位执行一次。在分钟字段,*/5表示每 5 分钟。
4.2 Quartz 等扩展常见特殊字符
?(问号):仅用于“日期”和“星期”字段,表示“不指定”。当其中一个字段被指定具体值时,另一个常设为?以避免冲突。L(Last):表示“最后”。在“日期”字段中可表示当月最后一天;在“星期”字段中可表示最后一个星期几(不同实现语义略有差异)。W(Weekday):表示“工作日”。常用于“日期”字段,表示离指定日期最近的工作日。#:用于“星期”字段,表示“第几个星期几”。例如2#1通常表示“每月第一个星期一”(以实现文档为准)。
5. 常用 Cron 表达式示例
5.1 Linux Crontab(5 字段)示例
| 表达式 | 含义 |
|---|---|
* * * * * | 每分钟执行一次 |
0 * * * * | 每小时的第 0 分钟执行(即整点执行) |
0 0 * * * | 每天凌晨 0 点执行 |
0 0 * * 0 | 每周日凌晨 0 点执行 |
0 0 1 * * | 每月 1 号凌晨 0 点执行 |
*/10 * * * * | 每 10 分钟执行一次 |
0 9-18 * * * | 每天 9 点到 18 点的整点执行 |
0 9,12,18 * * * | 每天 9 点、12 点、18 点整执行 |
0 0 * * 1-5 | 每周一到周五凌晨 0 点执行(工作日) |
0 0 * * 6,0 | 每周六、周日凌晨 0 点执行(周末) |
5.2 Quartz(6 字段,含秒)示例
| 表达式 | 含义 |
|---|---|
0 * * * * ? | 每分钟执行一次(秒为 0) |
0 0 * * * ? | 每小时整点执行 |
0 0 0 * * ? | 每天 00:00:00 执行 |
0 30 23 L * ? | 每月最后一天 23:30:00 执行 |
0 0 12 ? * MON-FRI | 每个工作日中午 12:00:00 执行 |
6. 高级技巧与注意事项
6.1 环境变量
Cron 任务执行时的环境变量通常很少,可能只有 HOME、LOGNAME、SHELL 和有限的 PATH。因此,在脚本中最好使用绝对路径来调用命令和文件,或者在脚本开头显式设置 PATH。
6.2 输出重定向
Cron 任务执行后的输出(标准输出和标准错误)通常会通过邮件发送给用户。如果你不希望收到邮件,或者希望将日志保存到文件,请务必进行重定向:
# 将标准输出和错误输出都重定向到 /dev/null (丢弃)
0 * * * * /path/to/script.sh > /dev/null 2>&1
# 将日志追加到文件
0 * * * * /path/to/script.sh >> /var/log/myjob.log 2>&1
6.3 避免”雪崩”
如果你有大量的定时任务都在 0 0 * * *(午夜)执行,可能会导致系统负载瞬间飙升。建议错开执行时间,例如:
- 任务 A:
3 0 * * * - 任务 B:
17 0 * * *
6.4 日期与星期匹配规则(Linux)
很多人会把“日期”和“星期”字段理解为“同时满足才触发”,但在常见的 Linux Cron 实现中,如果两者都被限制为非 * 的值,通常是“或”的关系:满足其一就会触发。为了避免意外的触发频率,通常建议:
- 只在“日期”或“星期”其中一个字段写具体限制
- 另一个字段保持
*
6.5 时区与夏令时
Cron 通常使用系统时区运行。在夏令时(DST)切换日,某些时间点可能会“跳过”或“重复”,导致任务少跑一次或多跑一次。对严格的业务调度,建议显式指定时区(若调度器支持),或在任务内部做幂等与去重。
6.6 预定义宏(部分 Linux Cron 支持)
一些实现支持更直观的写法,例如:
@reboot:系统启动后执行@hourly/@daily/@weekly/@monthly/@yearly:按固定周期执行
6.7 不同的 Cron 实现
- System Cron: Linux 系统自带的,配置文件在
/etc/crontab或/var/spool/cron/。 - Quartz / Spring Schedule: Java 开发中常用的调度框架,支持秒级精度(6 或 7 个字段)。
- Node-cron: Node.js 中的 Cron 实现。
不同的实现对特殊字符(如 L, W, #, ?)的支持程度不同,编写时需参考具体文档。
7. 结语
掌握 Cron 表达式是每个开发者的基本功。虽然语法简单,但组合起来千变万化。
为了避免手动计算出错,强烈建议在部署前使用工具进行验证。记得收藏我们的 Cron 表达式生成器,让定时任务配置变得简单高效。