3.15 Cron 定时任务高级应用
预计阅读时间:18 分钟
📖 目录
学习目标
学完本章后,你将能够:
- 掌握 crontab 五字段语法及特殊字符串
@reboot、@daily等 - 配置 cron 的环境变量并避免 PATH 陷阱
- 编写 systemd timer 替代传统 cron 任务
- 理解 anacron 的作用——解决"关机错过调度"问题
- 给 cron 任务配置日志记录与输出重定向
- 选择合适的定时任务方案(cron vs systemd timer vs anacron)
核心知识
- crontab 语法——
分 时 日 月 周 命令,五个时间字段分别控制分钟(0-59)、小时(0-23)、日期(1-31)、月份(1-12)、星期(0-7,0/7=周日) - 特殊字符串——
@reboot(开机启动)、@daily/@midnight(每天0点)、@hourly、@weekly、@monthly、@yearly - cron 环境变量——cron 在最小化 Shell 环境中执行任务,
PATH默认只有/usr/bin:/bin,HOME为当前用户家目录 - systemd timer——由
.timer+.service两个 unit 组成,timer 触发 service 执行。支持单调(Monotonic)和日历(Calendar)两种时间表达 - anacron——为"不需要精确时间、只要在指定周期内运行一次"的场景设计。即使系统关机错过调度,恢复后自动补跑
- 日志与输出——cron 默认将 stdout/stderr 通过邮件发送给用户;systemd timer 输出由 journald 捕获;二者均可重定向到日志文件
- flock 防并发——使用
flock -n <lockfile> <command>防止同一 cron 任务在前一次未完成时再次启动
知识关联
- 前置知识:2.12:systemd 深入「systemd 深入」——理解 systemd unit 是理解 timer 的前置;4.19:Shell 实战案例集「Shell 实战案例集」——cron 执行的大多是 Shell 脚本
- 后续影响:定时任务是运维自动化的基石——备份(3.13:备份策略与恢复 备份策略与恢复)、日志轮转、监控采集(3.12:系统监控与告警 系统监控方案)、证书续期(3.11:SSL/TLS 证书管理 SSL/TLS 证书管理)都依赖它
- 配套技术:2.7:日志与故障排查「日志与故障排查」——cron 输出关联到日志分析;4.1:Ansible 自动化「Ansible 自动化运维」——ansible 可批量管理各节点 crontab
- 在整个体系中的位置:这是从"手动管理"到"自动化运维"的关键枢纽。无论用 cron 还是 systemd timer,定时调度是每个生产系统必备的基础设施
原理讲解
1. cron——最经典的定时调度器
cron 是 Linux 中最古老的定时任务守护进程。它的工作模型是"永远在后台等待,每分钟醒来检查一次是否有需要触发的任务":
crontab 文件层级:
| 类型 | 路径 | 管理方式 | 适用场景 |
|---|---|---|---|
| 用户 crontab | /var/spool/cron/crontabs/<user> | crontab -e | 普通用户定时任务 |
| 系统 crontab | /etc/crontab | 直接编辑,需指定用户列 | 系统级任务 |
| 片段目录 | /etc/cron.d/ | 放入文件即可 | 软件包自带定时任务 |
| run-parts 目录 | /etc/cron.hourly/ /etc/cron.daily/ /etc/cron.weekly/ /etc/cron.monthly/ | 放入可执行脚本 | 按周期批量执行 |
用户 crontab 语法:
# ┌────── 分钟 (0-59)
# │ ┌───── 小时 (0-23)
# │ │ ┌───── 日期 (1-31)
# │ │ │ ┌───── 月份 (1-12)
# │ │ │ │ ┌───── 星期 (0-7,0/7=周日)
# * * * * * 命令
时间字段特殊符号:
| 符号 | 含义 | 示例 |
|---|---|---|
* | 每个(every) | * * * * * 每分钟 |
*/N | 每隔 N 个单位 | */5 * * * * 每5分钟 |
M-N | 范围 | 9-17 9点到17点 |
A,B,C | 列表 | 1,15 1号和15号 |
M-N/P | 范围内每隔 P | 0-30/10 每10分钟前半小时 |
2. systemd timer——cron 的现代替代
systemd timer 是 systemd 原生支持的定时机制。它的优势在于与 systemd 生态完全整合:
# 两种时间表达
# 1. 日历时间(OnCalendar)——类似 crontab 的精确时间点
OnCalendar=*-*-* 02:00:00 # 每天凌晨2点
OnCalendar=Mon..Fri 09:00:00 # 工作日上午9点
OnCalendar=*-*-1..7 00:00:00 # 每月前7天
# 2. 单调时间(OnUnitActiveSec)——相对启动/上次触发的时间间隔
OnBootSec=5min # 启动后5分钟
OnUnitActiveSec=1h # 上次触发后1小时
OnUnitInactiveSec=30m # 上次停止后30分钟
cron vs systemd timer 对比:
| 特性 | cron | systemd timer |
|---|---|---|
| 精度 | 分钟级 | 秒级 |
| 时间表达 | 五字段 | 日历 + 单调 + 混合 |
| 依赖管理 | 无 | 支持 After/Requires |
| 资源限制 | 无 | CPUQuota/MemoryMax 等 cgroup 限制 |
| 日志 | 邮件或重定向 | journald 统管 |
| 错过调度 | 不补跑 | Persistent=true 可补跑 |
| 随机延迟 | 无 | RandomizedDelaySec |
3. anacron——解决"关机错过"问题
anacron(anachronistic cron)不为"精确时间点"设计,而是"只要在周期内执行一次即可"。它记录上次执行时间戳到 /var/spool/anacron/,启动时检查是否超过周期;如果系统关机错过,下次开机后补跑:
# /etc/anacrontab 格式
# period delay job-identifier command
1 5 cron.daily run-parts /etc/cron.daily
7 10 cron.weekly run-parts /etc/cron.weekly
30 15 cron.monthly run-parts /etc/cron.monthly
以上实际是大多数发行版的默认行为——cron 每小时执行 run-parts /etc/cron.hourly,而 cron.daily/weekly/monthly 调用的是 anacron。这确保了笔记本用户即使有大量离线时间也不会错过系统维护任务。
4. cron 的任务执行流程与运行环境
理解 cron 如何执行任务,是排查"单独跑正常、cron 里就失败"类问题的钥匙。一次完整执行包含五个阶段:
- 调度匹配:crond 守护进程每分钟醒来,逐条比对 crontab 中的时间字段
- 环境构造:crond 从
/etc/crontab、/etc/cron.d/*以及用户 crontab 头部的环境变量行构造最小环境(HOME=用户家目录,PATH=/usr/bin:/bin,SHELL=/bin/sh) - fork + exec:以任务所属用户的身份 fork 子进程执行命令(不经过登录 shell,
/etc/profile、~/.bashrc都不加载) - 输出捕获:stdout/stderr 被捕获,若有输出则通过
sendmail发给MAILTO指定的邮箱 - 日志记录:在 syslog 中写入一条
CMD记录
# 观察 cron 的执行痕迹(第 5 阶段)
grep CRON /var/log/syslog | tail -5
# 输出: Jul 30 02:00:01 host CRON[1234]: (root) CMD (/usr/local/bin/backup.sh)
# Jul 30 02:00:02 host CRON[1235]: (root) CMD (test -x /usr/sbin/anacron && ...)
# 验证"不加载交互式环境"这一事实:
# 把以下两行加入 crontab,对比输出即可证明
# * * * * * echo "PATH=$PATH" >> /tmp/cron-env.txt
# * * * * * whoami >> /tmp/cron-env.txt
# 手工执行 echo $PATH 的结果完全不同
5. 定时任务安全:访问控制与最小权限
cron 提供两层访问控制文件:/etc/cron.allow(白名单,存在则只有名单内用户可用 crontab)和 /etc/cron.deny(黑名单)。两个文件都不存在时,多数发行版默认只允许 root 使用 crontab——这正是很多教程里"普通用户 crontab -e 报权限不足"的原因。
# 白名单:只有列出的用户可以创建 crontab
# /etc/cron.allow
root
alice
# 黑名单:禁止特定用户(当 cron.allow 不存在时生效)
# /etc/cron.deny
guest
# 校验当前用户是否有 crontab 权限
crontab -l || echo "no crontab or not permitted"
# 安全建议:
# 1. 系统任务统一放 /etc/crontab 或 /etc/cron.d/,由 root 管理
# 2. 业务任务创建专用低权限用户执行,避免全部用 root
# 3. 敏感任务(备份、证书续期)优先放 /etc/cron.d/ 便于审计
示例代码
1. 基础 crontab 实例
# 每分钟执行 —— 调试用
*/1 * * * * /usr/local/bin/health-check.sh
# 每天凌晨2:30执行备份(带日志)
30 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
# 工作日9-18点每小时检查一次
0 9-18 * * 1-5 /usr/local/bin/check-service.sh
# 每月1号和15号凌晨3点清理
0 3 1,15 * * /usr/local/bin/cleanup.sh
# 每月最后一天执行(次月1日前一天)
0 0 28-31 * * [ "$(date +\%d -d tomorrow)" = "01" ] && /usr/local/bin/monthly-report.sh
# @reboot —— 开机启动(不是用户登录)
@reboot /usr/local/bin/startup-tasks.sh
2. 完整 crontab 环境变量设置
# /etc/crontab 环境变量 —— 避免"命令找不到"陷阱
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=admin@example.com
HOME=/root
LOGNAME=root
# 系统 crontab 需指定用户
30 2 * * * root /usr/local/bin/backup.sh
3. systemd timer 完整实例——备份任务
# /etc/systemd/system/backup.service
[Unit]
Description=Daily backup
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
StandardOutput=journal
StandardError=journal
# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily at 2am
Requires=backup.service
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true # 错过则补跑
RandomizedDelaySec=300 # 随机延迟0-5分钟
Unit=backup.service
[Install]
WantedBy=timers.target
# 启用
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer # 输出: Created symlink /etc/systemd/system/timers.target.wants/backup.timer
systemctl list-timers # 输出: NEXT LEFT LAST PASSED UNIT ACTIVATES
systemctl status backup.timer # 输出: ● backup.timer - Run backup daily at 2am
4. 日志配置与调试
# 方法1:cron 输出重定向到文件
30 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
# 方法2:用 logger 发送到 syslog
30 2 * * * /usr/local/bin/backup.sh 2>&1 | logger -t backup
# 方法3:systemd timer 通过 journald 查看
journalctl -u backup.service # 输出: -- Logs begin at ..., end at ... --
journalctl -u backup.timer # 输出: -- Logs begin at ..., end at ... --
journalctl --since "1 hour ago" -u backup.service
# 方法4:cron 自身日志
grep CRON /var/log/syslog # 输出: Jul 30 02:00:01 host CRON[1234]: (root) CMD (/usr/local/bin/backup.sh)
# Ubuntu/Debian 在 /var/log/syslog;RHEL 系在 /var/log/cron
# 调试技巧:手工跑一次测试
sudo -u www-data /usr/local/bin/script.sh
# 用 flock 防并发
30 2 * * * flock -n /tmp/backup.lock /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
5. 高级 crontab 技巧
# 错峰执行:同一分钟大量任务并发会拉高负载,分散到不同分钟
# 不好的写法(10 个任务都在 0 分触发)
0 * * * * /opt/jobs/clean-tmp.sh
0 * * * * /opt/jobs/sync-cache.sh
# 更好的写法:按分钟错开
0 * * * * /opt/jobs/clean-tmp.sh
5 * * * * /opt/jobs/sync-cache.sh
10 * * * * /opt/jobs/rotate-log.sh
# 随机化启动时间:避免整点雷击(1-59 分钟内随机挑一分执行)
# 注意:cron 的 SHELL=/bin/sh(dash)没有 $RANDOM,用 date +%N 生成随机纳秒数
# (10# 前缀防止前导零被当作八进制;crontab 中的 % 需转义为 \%)
*/5 * * * * sleep $((10#$(date +\%N) % 60)) && /opt/jobs/heartbeat.sh
# @reboot 深入:延迟执行,等待网络/服务就绪
@reboot sleep 30 && /usr/local/bin/startup-tasks.sh
# 每月最后一天 23:30(次月 1 日判断法,% 需转义)
30 23 28-31 * * [ "$(date +\%d -d tomorrow)" = "01" ] && /usr/local/bin/end-of-month.sh
# 每季度首日(1/4/7/10 月的 1 号)
0 4 1 1,4,7,10 * /usr/local/bin/quarterly-report.sh
# 周报:每周一早上 8 点
0 8 * * 1 /usr/local/bin/weekly-summary.sh
# 任务超时保护:timeout 命令兜底,防止脚本死循环
30 2 * * * timeout 3600 /usr/local/bin/heavy-job.sh >> /var/log/heavy.log 2>&1
6. anacron 深入配置
# /etc/anacrontab 完整格式说明
# period delay job-identifier command
# └周期天数 └延迟分钟 └任务ID(唯一) └实际命令
1 5 cron.daily run-parts /etc/cron.daily
7 10 cron.weekly run-parts /etc/cron.weekly
30 15 cron.monthly run-parts /etc/cron.monthly
# 自定义 anacron 任务:每周至少运行一次数据归档
# 7 20 data-archive /usr/local/bin/archive.sh >> /var/log/archive.log 2>&1
# anacron 关键配置(/etc/default/anacron)
# RANDOM_DELAY=45 # 补跑时随机延迟 0-45 分钟,避免多机同时补跑
# START_HOURS_RANGE=3-22 # 只在 3:00-22:00 之间检查补跑
# 查看上次运行时间戳(anacron 用它判断是否到期)
cat /var/spool/anacron/cron.daily
# 输出: 20260730 ← 上次执行的日期,超过周期天数则触发补跑
# 手动强制触发
anacron -f -d # -f 忽略时间戳强制运行,-d 前台调试模式
# 查看 anacron 是否活跃
systemctl status anacron.timer
# 输出: ● anacron.timer - Trigger anacron every hour
# Active: active (waiting)
7. 脚本幂等性与健壮性
定时任务可能因重叠执行、手工重跑、故障重试而多次运行。一个健壮的脚本必须幂等——无论执行多少次,最终结果一致,且不会造成副作用。这与 Ansible 等配置管理工具的幂等性理念一致:不是"重复执行会怎样",而是"重复执行也不该出事"。
# 幂等写法示例:备份脚本(同名文件直接覆盖即可)
#!/bin/bash
set -euo pipefail # 严格模式:变量未定义/管道失败立即退出
# 防并发:exec 打开锁文件并持有 fd 9,flock 加锁后主逻辑全程持锁
# (不要用 flock -c "command",子 shell 退出即释放锁,主逻辑等于没锁)
LOCKFILE=/tmp/backup.lock
exec 9> "$LOCKFILE"
if ! flock -n 9; then
echo "$(date) backup already running, skip" >> /var/log/backup.log
exit 0 # 幂等:直接退出,而不是报错
fi
echo $$ >&9 # 锁内记录持有者 PID,方便排查
# 幂等示例:插入唯一记录(重复执行不产生重复数据)
# INSERT ... ON DUPLICATE KEY UPDATE / INSERT ... ON CONFLICT DO NOTHING
# 幂等示例:创建目录与文件(已存在则跳过)
mkdir -p /var/lib/myapp # 已存在不报错
# 失败可重试:任务完成后写标记文件
if [ -f /var/run/myapp.done ] && [ -z "${FORCE_RUN:-}" ]; then
echo "already done, pass" && exit 0
fi
# ... 主逻辑 ...
touch /var/run/myapp.done
set -e 任何命令失败立即退出;set -u 使用未定义变量报错;set -o pipefail 管道中任一命令失败即失败。三个一起用,能拦截绝大多数"静默失败",配合 cron 的输出重定向,失败就会留痕。
8. 定时任务排错流程
任务不执行或执行异常时,按以下顺序排查,避免在错误层面浪费时间:
# 第一步:确认 crontab 真的在(语法正确)
crontab -l # 或 crontab -e 检查当前用户任务
systemctl status cron # cron 服务本身是否在运行
# 第二步:确认调度时间正确(最常见的低级错误)
# 用 crontab.guru 校验表达式语义:
# 0 2 * * * 每天凌晨2点 ✓
# * 2 * * * 每天2点内每分钟 ✗(往往不是本意)
date # 核对服务器时区与时间(UTC vs CST 差 8 小时)
# 第三步:确认 cron 真的触发了
grep "CMD" /var/log/syslog | grep backup | tail -5
# 没有记录 → 调度/权限问题;有记录 → 命令本身问题,进第四步
# 第四步:手工以相同身份执行,对比输出
sudo -u root /usr/local/bin/backup.sh
sudo -u www-data /usr/local/bin/backup.sh # 以任务实际用户身份跑
# 手工能跑、cron 不能跑 → PATH/环境问题,检查脚本内是否用了相对路径
# 第五步:检查输出捕获与邮件
ls /var/mail/root # 邮件默认存放位置,MAILTO 未设置时
grep "backup" /var/log/mail.log 2>/dev/null
# 第六步:检查脚本自身日志与退出码
echo "exit code: $?" # cron 失败时退出码通常为 1
# 脚本中每步都打日志,避免"黑盒":
# set -x 调试模式输出每一条执行语句
常见错误
| 错误/误区 | 解决方案 | |
|---|---|---|
| "cron 任务不执行,脚本单独跑没问题" | 最常见的原因:cron 的 PATH 不包含脚本中使用的命令路径。在 crontab 头部设置 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin。 | |
| "忘记输出重定向,cron 卡住或发邮件" | cron 默认将 stdout/stderr 发邮件给用户。不加 MAILTO="" 且没有重定向,邮件积累可能阻塞 cron。通常加 >& /dev/null 或 >> /var/log/xxx.log 2>&1。 | |
| "在 crontab 里用 % 出问题" | % 在 crontab 中有特殊含义(换行符)。在命令中使用 % 必须转义:date +\%Y\%m\%d。 | |
| "脚本中用了相对路径" | cron 的工作目录是用户 HOME。脚本中用相对路径会找不到文件。总是使用绝对路径或脚本内部先 cd "$(dirname "$0")"。 | |
"用 @reboot 但任务没执行" | @reboot 在 cron 守护进程启动时触发,而非用户登录时。若机器持续运行,重启 cron 服务也会触发。若依赖网络等资源,需在脚本内添加等待。 | |
| "同一时间多个 cron 任务重叠导致并发问题" | 使用 flock -n 确保同一时间只运行一个实例。或者拆分成不同时间点错峰执行。 | |
| "crontab 语法检查不过关" | 推荐使用 https://crontab.guru 验证表达式。crontab -e 保存时 crontab 命令本身会做基本字段校验;cronic 不是校验器,它是输出封装器(成功时静默、失败时才输出/告警)。 | |
| "crontab -e 报 permission denied,但我是管理员" | 系统存在 /etc/cron.allow 白名单,当前用户不在其中;或 /etc/cron.deny 包含当前用户 | 检查并编辑 /etc/cron.allow 加入用户;确认不是被 deny 文件拒绝 |
| "脚本出现不可见字符/回车符导致执行异常" | Windows 编辑器写入的 CRLF 行尾在 Linux 下引发 /bin/sh^M: bad interpreter | sed -i 's/\r$//' script.sh 转换行尾;编辑器统一用 LF |
| "任务执行了但结果不对,时区差 8 小时" | 系统时区为 UTC,业务预期是 CST(UTC+8) | timedatectl set-timezone Asia/Shanghai;跨时区场景在脚本内用 TZ=Asia/Shanghai date |
| "多台机器同时点执行导致数据库/后端打爆" | 所有节点的 cron 都在整点触发,形成流量尖峰 | 每台机器错开分钟;或 systemd timer 用 RandomizedDelaySec |
最佳实践
| # | 建议 | 说明 |
|---|---|---|
| 1 | 总是在 crontab 起始处显式设置 PATH | 避免"单独跑可以,cron 执行找不到命令"。PATH 至少包含 /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin。 |
| 2 | 所有路径使用绝对路径 | 包括命令路径、脚本路径、日志文件路径。避免依赖相对路径或 PATH 搜索。 |
| 3 | 输出重定向到日志文件 | >> /var/log/cron/xxx.log 2>&1 记录执行结果。需要时设置 MAILTO="" 关闭默认邮件通知。 |
| 4 | 给关键任务加 flock 防并发 | flock -n /tmp/xxx.lock 防止同一脚本在前一次未完成时被再次触发。 |
| 5 | 新部署先缩短测试间隔 | 先用 */1 * * * * 每1分钟测试确认脚本正常,稳定后再改回正式调度。 |
| 6 | 考虑用 systemd timer 替代复杂 cron | 需要秒级精度、依赖管理、资源限制、错过补跑等场景时,systemd timer 是更好的选择。 |
| 7 | 日志轮转管理 cron 日志 | cron 自己的日志和任务输出日志都要配置 logrotate,防止磁盘写满。参考 4.8:集中式日志管理「集中式日志管理方案」。 |
| 8 | 脚本内部做好幂等性 | 无论重复执行多少次,结果一致。防止因意外重叠或重复调度导致的数据损坏。 |
| 9 | 生产脚本开启 set -euo pipefail | 任何步骤失败立即退出并留痕,避免"看起来成功"的静默失败。手工跑成功≠cron 里成功。 |
| 10 | 错峰与随机延迟分散任务 | 多任务集中在整点会造成 IO/CPU 尖峰;RANDOM_DELAY 或 RandomizedDelaySec 可自动分散。 |
| 11 | 为长任务设置超时兜底 | timeout 3600 /path/script.sh 防止死循环任务无限占用资源。 |
| 12 | 权限最小化 | 能用专用低权限用户跑的业务任务不要用 root;白名单 /etc/cron.allow 控制可创建 crontab 的用户。 |
练习题
- (概念)cron 的
@reboot和 systemd timer 的OnBootSec有什么区别?各自的适用场景是什么? - (概念)anacron 解决了 cron 的什么不足?在什么场景下应该优先使用 anacron?
- (实操)编写一个 crontab 条目:每个工作日上午 9:05 执行
/usr/local/bin/check-disk.sh,输出追加到/var/log/disk-check.log,错误也一并追加。 - (实操)创建一个 systemd timer:每天凌晨 3:30 执行
/usr/local/bin/db-backup.sh,要求支持错过补跑(Persistent=true)。写出完整的.service和.timer文件及启用命令。 - (探究 🔍)查看你当前系统的
/etc/anacrontab、/etc/crontab和systemctl list-timers的输出。回答:你系统上的cron.daily任务实际上是由 cron 还是 anacron 触发的?如何验证?systemd timer 当前有哪些活跃条目?
点击查看答案
- @reboot 在 cron 守护进程启动时触发,适用于依赖 cron 环境的任务。OnBootSec 是 systemd timer 的单调时间表达式,在系统启动后固定延迟触发,精度秒级,支持依赖管理和资源限制。
- anacron 解决 cron 在系统关机时错过调度的问题。适合不需要精确执行时间、只需在周期内运行一次的场景(如 daily 维护任务、日志轮转、安全更新)。
5 9 * * 1-5 /usr/local/bin/check-disk.sh >> /var/log/disk-check.log 2>&1/etc/systemd/system/db-backup.service:[Service] Type=oneshot; ExecStart=/usr/local/bin/db-backup.sh。/etc/systemd/system/db-backup.timer:[Timer] OnCalendar=*-*-* 03:30:00; Persistent=true; Unit=db-backup.service。[Install] WantedBy=timers.target。启用:systemctl daemon-reload && systemctl enable --now db-backup.timer。- 查看
/etc/anacrontab和/etc/crontab。大多数发行版 cron.hourly 由 cron 触发,cron.daily 实际调用 anacron——验证方法:查看/etc/crontab中是否有一行调用run-parts /etc/cron.daily,再看 anacron 是否记录了时间戳。systemctl list-timers 显示所有活跃的 systemd timer。
学习检查点
学完本章后,请检验自己是否掌握以下内容:
| 检查项 | 自测问题 | 验证方法 |
|---|---|---|
| 概念理解 | 能用自己的话解释 Cron 表达式的各个字段含义 | 尝试向他人讲解 |
| 命令操作 | 能不查文档完成 Cron 任务创建、编辑、删除、日志查看 | 在终端实际执行 |
| 原理掌握 | 能说出 Cron 守护进程的工作原理和任务执行流程 | 画出流程图 |
| 故障排查 | 能独立排查 Cron 任务未执行、环境变量问题、权限错误 | 模拟故障并修复 |
| 最佳实践 | 能说明为什么需要为 Cron 任务配置日志和错误处理 | 对比不同方案 |
本章总结
定时任务是系统自动化的基础设施。cron 覆盖面最广、生态最成熟;systemd timer 更现代、功能更强,适合与 systemd 生态深度整合的场景;anacron 专门解决"不精确但必须执行"的需求。选型要看对精度、依赖、日志和可移植性的要求。
速查表
| 概念 | 一句话定义 |
|---|---|
| crontab 五字段 | 分 时 日 月 周——精确到分钟的调度表达 |
| @reboot | cron 守护进程启动时执行一次 |
| systemd timer | 由 .timer + .service 组成,支持日历和单调两种时间 |
| anacron | 周期内至少执行一次,错过关机时间则补跑 |
| flock | 文件锁防止同一任务并发执行 |
| Persistent=true | systemd timer 错过调度后自动补跑 |
| RandomizedDelaySec | 随机延迟避免多个 timers 同时触发造成负载尖峰 |
| /etc/cron.allow | crontab 白名单,存在时只有名单内用户可用 |
| anacron -f -d | 强制忽略时间戳运行 / 前台调试模式 |
| timeout N cmd | 为命令设置超时上限,防死循环 |
| crontab -l | 列出当前用户的定时任务(排查第一步) |
学习路径:掌握本章后,继续学习 4.19:Shell 实战案例集「Shell 实战案例集」编写健壮的 cron 执行脚本 → 3.13:备份策略与恢复「备份策略与灾难恢复方案」设计完整备份体系 → 4.8:集中式日志管理「集中式日志管理方案」统一收集 cron 执行日志。
延伸阅读
- 手册:
man 5 crontab、man 8 cron、man 5 anacrontab、man 8 anacron、man 7 systemd.timer - 在线工具:crontab.guru——交互式 crontab 表达式校验与解释
- systemd 日历事件:
systemd-analyze calendar "Mon..Fri 09:00:00"校验和解释日历表达式 - 文章:"systemd timers vs cron"(搜索该关键词可找到多篇深入对比)
- 相关命令:
cronic(封装 cron 输出)、whenever(Ruby cron 包装)、at(一次性定时任务)