Linux Cron 速查表
你已经将 Node 应用部署到 Linux 服务器上,需要一个脚本在每天凌晨 3 点运行。你听说过 cron,但语法看起来很晦涩,而且你找到的教程要么过时,要么充满错误。这份 Linux cron 速查表为你提供了正确的、考虑发行版差异的参考,帮助你可靠地调度 cron 任务。
核心要点
- Cron 使用五字段格式(分钟、小时、日期、月份、星期几),后跟要执行的命令。
- 当同时指定日期和星期几时,cron 将它们视为 OR(或)关系而非 AND(与)关系——这是导致意外行为的常见原因。
- Cron 在有限的、依赖发行版的环境中运行,因此始终使用绝对路径并显式设置 PATH 以确保可移植性。
- 不同的 Linux 发行版使用不同的 cron 实现,功能支持各不相同。
Crontab 语法:五字段格式
每个 cron 任务遵循以下结构:
┌───────────── 分钟 (0-59)
│ ┌─────────── 小时 (0-23)
│ │ ┌───────── 日期 (1-31)
│ │ │ ┌─────── 月份 (1-12)
│ │ │ │ ┌───── 星期几 (0-6, 星期日=0)
│ │ │ │ │
* * * * * command
特殊字符:
*— 任意值,— 列表分隔符 (1,3,5)-— 范围 (1-5)/— 步长值 (*/15 表示每 15 个单位)
重要提示: 像 L、W、# 和 ? 这样的字符是 Quartz 调度器语法,不是标准 cron 语法。不要在 Linux crontab 中使用它们。如有疑问,请通过 man 5 crontab 查看系统自带的文档。
常见调度模式
*/5 * * * * # 每 5 分钟
0 * * * * # 每小时整点
0 3 * * * # 每天凌晨 3 点
0 0 * * 0 # 每周日午夜
0 0 1 * * # 每月第一天
特殊字符串
大多数 cron 实现支持这些快捷方式(在 BusyBox 等精简系统上支持可能有所不同):
| 字符串 | 等效表达式 |
|---|---|
@reboot | 启动时运行一次 |
@hourly | 0 * * * * |
@daily | 0 0 * * * |
@weekly | 0 0 * * 0 |
@monthly | 0 0 1 * * |
@yearly | 0 0 1 1 * |
注意 @reboot 不能保证网络或其他服务可用;对于需要依赖关系的启动任务,systemd timer 通常是更好的选择。
日期 vs 星期几的陷阱
当你同时指定日期和星期几时,cron 将它们视为 OR(或)关系,而非 AND(与)关系:
0 0 15 * 1 # 在 15 号或任何星期一运行
这让很多人措手不及。如果你需要”15 号,但仅当它是星期一时”,请在脚本内部处理该逻辑。
环境处理
Cron 在有限的非交互式环境中运行。这是大多数任务静默失败的原因。
PATH 行为因发行版和版本而异:
- 某些系统定义了最小的默认 PATH
- 其他系统(特别是较新的 Ubuntu 版本)可能从服务环境继承 PATH
不要依赖默认值。为了可移植和可预测的行为,请显式设置所需内容。
安全实践:
# 在 crontab 顶部设置变量
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=""
# 始终使用绝对路径
0 3 * * * /usr/bin/node /home/deploy/app/cleanup.js
注意: MAILTO 仅在安装并配置了本地 MTA 时才有效。许多现代服务器没有 MTA。请显式重定向输出,而不是依赖电子邮件。
Discover how at OpenReplay.com.
输出和日志记录
# 记录所有内容
0 3 * * * /path/to/script.sh >> /var/log/myjob.log 2>&1
# 丢弃所有输出
0 3 * * * /path/to/script.sh >/dev/null 2>&1
# 仅记录错误
0 3 * * * /path/to/script.sh >/dev/null 2>> /var/log/myjob-errors.log
基本 Crontab 命令
crontab -e # 编辑你的 crontab
crontab -l # 列出当前任务
crontab -r # 删除所有任务(小心!)
对于系统级任务,使用 /etc/cron.d/ 文件。注意 /etc/cron.daily/、/etc/cron.hourly/ 等是通过 run-parts 执行的,不会被 cron 自动扫描。有关命名和执行规则,请参阅 man 8 run-parts。
Cron 实现各不相同
不同系统运行不同的 cron 守护进程:
- Debian/Ubuntu: cron (Vixie 系列,发行版打补丁版本)
- RHEL/Fedora: Cronie
- Alpine/容器: BusyBox
crond
功能支持(特殊字符串、邮件行为、日志记录)可能有所不同。始终根据本地 crontab(5) 手册页进行验证。
Cron vs Systemd Timer
| 考虑因素 | Cron | Systemd Timer |
|---|---|---|
| 设置复杂度 | 简单 | 更冗长 |
| 错过任务处理 | 跳过 | 可配置 (Persistent=true) |
| 依赖关系 | 无 | 可以等待服务/挂载 |
| 日志记录 | 手动 | 内置 journald |
使用 cron 的场景: 你需要在任何地方都能工作的简单、可移植的调度。
使用 systemd timer 的场景: 你需要依赖管理、跨重启的持久化调度,或与现代 Linux 系统更好的集成。systemd 项目关于 timer 单元 的文档是权威参考。
快速调试检查清单
- Cron 是否正在运行?
systemctl status cron或systemctl status crond(服务名称因发行版而异) - 检查日志:
grep CRON /var/log/syslog(Debian/Ubuntu) 或/var/log/cron(RHEL/Fedora) - 在受限环境中手动测试你的命令
- 验证所有命令和文件的绝对路径
- 检查脚本的文件权限
结论
Cron 仍然是在 Linux 上调度任务的最简单方法。掌握五字段语法,理解组合日期字段时的 OR 行为,并考虑特定发行版的环境行为。有了这些基础知识,你的调度任务将可靠运行多年。
常见问题
最常见的原因是环境问题。Cron 在有限的非交互式环境中运行,该环境与你的 shell 不同,并且 PATH 行为因发行版而异。始终使用绝对路径,显式设置所需变量,验证 cron 服务正在运行,并检查系统日志中的错误。
使用星期几字段,范围从星期一 (1) 到星期五 (5)。例如,要在每个工作日上午 9 点运行,使用: 0 9 * * 1-5 /path/to/script.sh。请记住,在标准 cron 语法中,星期日是 0,星期六是 6。
用户 crontab 使用 crontab -e 编辑,按用户存储。/etc/cron.d/ 中的系统 crontab 在时间规范后包含一个额外的用户名字段,用于指示哪个用户运行该命令。系统 crontab 更适合服务和共享管理。
在模拟 cron 的最小环境中手动运行你的命令。例如: env -i PATH=/usr/bin:/bin /path/to/script.sh。这有助于发现缺失的依赖项或路径问题,否则会导致静默失败。
Gain control over your UX
See how users are using your site as if you were sitting next to them, learn and iterate faster with OpenReplay. — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.