指南

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)* , - /

注意

  1. 星期字段中,07 通常都代表星期日。
  2. 标准 Linux Cron 不支持秒级调度(最小粒度为分钟)。如果需要秒级,通常需要结合脚本循环或使用更高级的调度器。
  3. 在 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 为周一,以此类推) 请务必确认你的系统使用哪种标准!

这类表达式支持更多特殊字符(如 ?LW#),与 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 任务执行时的环境变量通常很少,可能只有 HOMELOGNAMESHELL 和有限的 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 表达式生成器,让定时任务配置变得简单高效。