Cron 表达式由五个用空格分隔的字段组成,用于告知 Unix 计时器在何时执行命令。五个字段、少量特殊字符和一些常见模式——这就是整个认知模型。本参考手册涵盖了语法、容易让人困惑的字符以及开发者实际使用的调度方案。
五个字段
标准 cron 使用五个位置字段:
* * * * *
│ │ │ │ └─ Day of week (0–7, Sunday = 0 or 7)
│ │ │ └─── Month (1–12)
│ │ └───── Day of month (1–31)
│ └─────── Hour (0–23)
└───────── Minute (0–59)
AWS EventBridge 和 Java 的 Quartz 计时器在前面增加了一个字段,总共变为六个字段。其余每个字段向右移动。这会困扰在不同环境中迁移的开发者——将一个 Quartz 表达式直接粘贴到标准 crontab 中,会以错误的时间运行,且没有任何警告。 秒 除非平台明确要求六个字段,否则请坚持使用五个字段的 POSIX cron。
坚持使用五字段POSIX cron,除非平台明确要求六字段。
特殊字符
| 字符 | 意义 | 例子 |
|---|---|---|
* | 任何值——匹配所有单位 | * * * * * ——每分钟 |
, | 值列表 | 0 9,17 * * * ——每天上午 9 点和下午 5 点 |
- | 范围 | 0 9-17 * * * ——每天上午 9 点到下午 5 点之间的每个小时 |
/ | 步长间隔 | */15 * * * * ——每 15 分钟 |
? | 无特定值(仅 Quartz/AWS 支持) | 0 0 15 * ? ——每月 15 日,任意工作日 |
L | 最后(仅 Quartz/AWS 支持) | 0 0 L * ? ——每月最后一天 |
W | 最近的工作日(仅 Quartz/AWS 支持) | 0 0 15W * ? ——距离 15 日最近的工作日 |
标准 crontab 仅识别 *, ,, -,并且 /。如果在表达式中看到 ?, L, 或者 W ,它原本是为 Quartz 或 AWS EventBridge 编写的——请勿直接将它粘贴到 Linux crontab 中而不做修改。
参考表:开发者实际使用的调度方案
这部分值得收藏。使用 IO Tools Cron 表达式生成器.
| 描述 | Cron 表达式 | 笔记 |
|---|---|---|
| 每分钟 | * * * * * | 在生产环境中很少适用 |
| 每 5 分钟 | */5 * * * * | 健康检查、短轮询周期 |
| 每15分钟 | */15 * * * * | 缓存预热、数据同步 |
| 每 30 分钟一次 | */30 * * * * | 等同于 0,30 * * * * |
| 每小时(整点) | 0 * * * * | 在每小时的 :00 时刻运行 |
| 每 6 小时一次 | 0 */6 * * * | 数据同步、增量导出 |
| 每天午夜 UTC | 0 0 * * * | 标准的每日批处理触发器 |
| 每天上午 9 点 UTC | 0 9 * * * | 早晨报告生成 |
| 工作日每天上午 9 点 UTC | 0 9 * * 1-5 | 仅工作日的作业(周一至周五) |
| 工作日每天上午 8:30 UTC | 30 8 * * 1-5 | 提前站会报告的发送 |
| 每周日早上 2 点 | 0 2 * * 0 | 每周维护、非高峰时段的备份 |
| 每月第一天 | 0 0 1 * * | 每月账单处理、周期性报告 |
| 1 月 1 日午夜 | 0 0 1 1 * | 年度重置、年初作业 |
时区陷阱
Cron 本身没有时区感知功能。它运行在服务器配置的时区下——在大多数 Linux 系统中,该时区为 UTC。这通常没有问题,直到涉及与工作时间相关的作业,或者用户分布在不同地区而困惑于“上午 9 点报告”为何在下午 2 点才到达。
最安全的默认设置:
- 将服务器设置为 UTC。在应用程序逻辑中转换为本地时间,而不是在 cron 表达式中进行转换。
- 为每个 cron 作业添加注释,注明其实际的本地时间,以便下一个阅读 crontab 的人不必猜测。
- 当使用云调度器(AWS EventBridge、Google Cloud Scheduler)时,请验证时区字段——大多数支持直接使用 IANA 时区名称,从而消除歧义。
# Always comment with the effective local time
# Runs daily at midnight UTC (= 8pm EST / 5pm PST)
0 0 * * * /usr/bin/python3 /opt/scripts/daily_report.py
测试:在部署前计算下一次运行时间
将 cron 作业部署到服务器后才发现它每分钟运行一次而非每小时运行,是每个开发者的必经之路。请跳过这一过程。
这 IO Tools Cron 下一次运行计算器 会精确显示您的表达式将在何时下一次触发——只需粘贴表达式,即可获取接下来的十次运行时间,而无需接触服务器。
用于命令行验证:
# Install croniter (Python) for quick expression testing
pip install croniter
python3 -c "
from croniter import croniter
from datetime import datetime
cron = croniter('*/15 * * * *', datetime.utcnow())
for _ in range(5):
print(cron.get_next(datetime))
"
在 Linux 上添加 cron 作业
# Open the crontab editor for the current user
crontab -e
# Format: minute hour day month weekday command
# Run backup script daily at 2:30am UTC
30 2 * * * /home/user/scripts/backup.sh >> /var/log/backup.log 2>&1
# Run a Python script every 5 minutes
*/5 * * * * /usr/bin/python3 /home/user/scripts/sync.py
# View current crontab entries
crontab -l
# Edit another user's crontab (requires root)
crontab -u www-data -e
这 2>&1 在备份行的末尾将 stderr 重定向到 stdout,使两者都进入日志文件。否则,cron 错误将进入邮件队列——而没有人会检查该队列。
GitHub Actions 计划工作流
GitHub Actions 使用相同的五字段 cron 语法,始终以 UTC 时间为准。不支持时区覆盖。
name: Nightly Data Export
on:
schedule:
# Runs at 1:00 AM UTC every weekday
- cron: "0 1 * * 1-5"
workflow_dispatch: # Allow manual trigger
jobs:
export:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run export script
run: python scripts/export.py
一个注意事项:在高负载期间,GitHub Actions 计划工作流可能会延迟最多 15 分钟。不要依赖它来满足需要精确时间的场景。
当标准 cron 不够用时
标准 cron 能够处理大多数单服务器场景。但在大规模系统中,其局限性会成为问题:
- 失败时无重试机制。 如果作业崩溃,下一次运行将为下一个预定时间——没有自动重试机制。
- 无分布式锁机制。 多个服务器运行相同的 crontab 会同时触发相同的作业。
- 无可观测性。 没有内置的运行历史、失败警报或运行时长跟踪仪表板。
| 问题 | 更好的替代方案 |
|---|---|
| 重试逻辑和任务队列 | Celery Beat(Python)、Sidekiq-Cron(Ruby) |
| 基于云的调度服务,支持重试 | AWS EventBridge + Lambda、Google Cloud Scheduler |
| CI/CD 流程触发器 | GitHub Actions 计划 |
| 可观察的作业编排 | Airflow、Prefect、Temporal |
对于单服务器上的脚本,cron 仍然是正确的工具——它简单、可靠且无依赖。对于需要重试保障、分布式执行或失败可见性的场景,专用的任务队列会迅速带来回报。
使用 Cron 表达式生成器 以构建您下一个调度方案,无需死记硬背语法,以及 Cron 下一次运行计算器 以验证它是否在预期时间触发。
