什么是 Cron?
Cron 是 Unix/Linux 系统中基于时间的任务调度器。它可以在指定的时间间隔(从每分钟到每年一次)运行命令或脚本,无需手动触发。
调度由 cron 表达式 定义:一个包含 5 个字段的字符串,描述何时运行。
Cron 表达式结构
┌─────────── 分钟 (0–59)
│ ┌───────── 小时 (0–23)
│ │ ┌─────── 日 (1–31)
│ │ │ ┌───── 月 (1–12 或 JAN–DEC)
│ │ │ │ ┌─── 星期 (0–7,0 和 7 表示星期日,或 SUN–SAT)
│ │ │ │ │
* * * * * 要执行的命令
每个字段可以是:
*— 任意值(“每”)- 数字 — 特定值
a,b— 列表a-b— 范围*/n— 每 n 个单位(步长)a-b/n— 带步长的范围
特殊字符说明
| 字符 | 示例 | 含义 |
|---|---|---|
* |
* * * * * |
每分钟 |
, |
0 9,17 * * * |
在 9:00 和 17:00 |
- |
0 9-17 * * * |
从 9 点到 17 点每小时 |
/ |
*/15 * * * * |
每 15 分钟 |
L |
0 0 L * * |
月份的最后一天(某些实现) |
? |
0 0 ? * MON |
无特定值(Quartz 调度器) |
命名快捷方式
许多 cron 实现支持以下便捷别名:
| 快捷方式 | 表达式 | 含义 |
|---|---|---|
@yearly 或 @annually |
0 0 1 1 * |
每年一次,1 月 1 日午夜 |
@monthly |
0 0 1 * * |
每月一次,1 日午夜 |
@weekly |
0 0 * * 0 |
每周一次,星期日午夜 |
@daily 或 @midnight |
0 0 * * * |
每天一次午夜 |
@hourly |
0 * * * * |
每小时一次 |
@reboot |
— | 启动时一次 |
30 多个实用 Cron 表达式示例
每 N 分钟/小时
* * * * * # 每分钟
*/5 * * * * # 每 5 分钟
*/10 * * * * # 每 10 分钟
*/15 * * * * # 每 15 分钟
*/30 * * * * # 每 30 分钟
0 * * * * # 每小时(:00 时)
0 */2 * * * # 每 2 小时
0 */6 * * * # 每 6 小时
0 */12 * * * # 每 12 小时
特定时间
0 0 * * * # 每天午夜
0 6 * * * # 每天上午 6:00
30 8 * * * # 每天上午 8:30
0 9-17 * * * # 从上午 9 点到下午 5 点每小时
0 9,12,15 * * * # 在上午 9 点、中午和下午 3 点
0 0 * * 0 # 每个星期日午夜
0 0 * * 1 # 每个星期一午夜
0 0 * * 1-5 # 每个工作日午夜
0 0 * * 6,0 # 每个周末午夜
每月和每年
0 0 1 * * # 每月第一天午夜
0 0 15 * * # 每月 15 日午夜
0 0 1,15 * * # 每月 1 日和 15 日
0 0 1 1 * # 1 月 1 日(新年)
0 0 1 */3 * # 每季度第一天
0 0 L * * # 月份最后一天(支持 L 的 cron)
实际任务示例
# 每天凌晨 2 点备份数据库
0 2 * * * /scripts/backup-db.sh
# 每个星期日凌晨 3 点清理临时文件
0 3 * * 0 find /tmp -mtime +7 -delete
# 每个星期一上午 9 点发送周报
0 9 * * 1 /scripts/send-weekly-report.sh
# 每月 1 日和 15 日凌晨 3 点续订 SSL 证书
0 3 1,15 * * certbot renew --quiet
# 每 30 分钟检查磁盘空间
*/30 * * * * /scripts/check-disk.sh
# 工作时间内每 5 分钟运行 Node.js 脚本
*/5 9-17 * * 1-5 node /app/sync-data.js
# 每晚 11 点重启服务
0 23 * * * systemctl restart myapp
# 每月 1 日凌晨 1 点归档日志
0 1 1 * * gzip /var/log/app/*.log
设置 Crontab
# 编辑当前用户的 crontab
crontab -e
# 列出当前 crontab
crontab -l
# 删除 crontab
crontab -r
# 编辑特定用户的 crontab(以 root 身份)
crontab -u www-data -e
示例 crontab 文件:
# 环境变量
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=admin@example.com
# 任务
0 2 * * * /home/ubuntu/backup.sh >> /var/log/backup.log 2>&1
*/5 * * * * /home/ubuntu/health-check.sh
0 9 * * 1 /home/ubuntu/weekly-report.sh
常见陷阱
1. PATH 问题
Cron 使用最小 PATH 运行。在 shell 中能正常运行的脚本在 cron 中可能因找不到命令而失败。
修复:在脚本中使用完整路径:
# 在 crontab 或脚本顶部:
PATH=/usr/local/bin:/usr/bin:/bin
# 或使用绝对路径
/usr/bin/python3 /home/ubuntu/script.py
2. 缺少输出捕获
除非设置了 MAILTO,否则 cron 默认丢弃 stdout/stderr。
# 将输出重定向到日志文件
0 2 * * * /scripts/backup.sh >> /var/log/backup.log 2>&1
# 抑制所有输出(谨慎使用)
0 2 * * * /scripts/backup.sh > /dev/null 2>&1
3. 任务重叠
如果任务执行时间超过间隔,可能会同时运行多个实例。通过以下方式防止:
*/5 * * * * flock -n /tmp/myjob.lock /scripts/myjob.sh
4. 星期编号
星期 0 和 7 都表示星期日,星期 1 表示星期一。使用特定日期时请仔细检查。
Cron 替代方案
| 工具 | 使用场景 |
|---|---|
| systemd timers | 现代 Linux,更好的日志记录 |
| Kubernetes CronJob | 基于容器的定时任务 |
| AWS EventBridge | 云原生调度 |
| GitHub Actions schedule | 基于 CI/CD 的自动化 |
| APScheduler (Python) | 进程内调度 |
| node-cron | Node.js 进程内调度 |
常见问题
问:cron 的最小间隔是多少? 1 分钟。Cron 不支持小于 1 分钟的间隔。对于频繁任务,请在长时间运行的进程中使用循环。
问:计算机关闭时 cron 会运行吗?
不会。如果系统在计划时间关闭,则该次运行会被跳过。对于错过也必须运行的任务,请使用 anacron。
问:为什么我的 cron 任务没有运行?
检查:cron 服务是否运行(systemctl status cron),语法是否正确,脚本中是否使用完整路径,文件权限是否正确,并查看 /var/log/syslog 中的错误。
问:如何在特定时区运行 cron 任务?
在 crontab 中设置 TZ:在任务前添加 TZ=America/New_York。或者使用 systemd timers,它们原生支持时区。
→ 使用 Crontab Generator 可视化生成 cron 表达式。