定时任务
定时任务允许你在指定的时间自动执行命令或脚本。Ubuntu 26.04 支持传统的 cron 和更现代的 systemd timers 两种方式。
crontab 基本用法
管理 crontab
# 编辑当前用户的 crontab
crontab -e
# 查看当前用户的 crontab
crontab -l
# 删除当前用户的 crontab
crontab -r
# 编辑其他用户的 crontab(需要 root 权限)
sudo crontab -u username -e
# 查看其他用户的 crontab
sudo crontab -u username -lcron 时间语法
cron 表达式由 5 个时间字段组成:
┌──────── 分钟 (0-59)
│ ┌────── 小时 (0-23)
│ │ ┌──── 日 (1-31)
│ │ │ ┌── 月 (1-12)
│ │ │ │ ┌ 星期 (0-7, 0和7都表示周日)
│ │ │ │ │
* * * * * command特殊字符
| 字符 | 说明 | 示例 |
|---|---|---|
* | 任意值 | * * * * * 每分钟 |
, | 多个值 | 1,15,30 * * * * 第1、15、30分钟 |
- | 范围 | 1-5 * * * * 第1到5分钟 |
/ | 步长 | */10 * * * * 每10分钟 |
常见示例
# 每分钟执行
* * * * * /path/to/script.sh
# 每小时执行(整点)
0 * * * * /path/to/script.sh
# 每天凌晨 3 点执行
0 3 * * * /path/to/script.sh
# 每天凌晨 3 点 30 分执行
30 3 * * * /path/to/script.sh
# 每周一凌晨 2 点执行
0 2 * * 1 /path/to/script.sh
# 每月 1 号凌晨执行
0 0 1 * * /path/to/script.sh
# 每 5 分钟执行
*/5 * * * * /path/to/script.sh
# 每小时的第 15 和 45 分钟执行
15,45 * * * * /path/to/script.sh
# 工作日(周一到周五)每天 9 点执行
0 9 * * 1-5 /path/to/script.sh
# 每天 8 点到 18 点,每小时执行
0 8-18 * * * /path/to/script.sh
# 每半年执行(1月和7月的1号)
0 0 1 1,7 * /path/to/script.sh特殊关键字
# 等价写法
@reboot # 系统启动时执行
@yearly # 每年执行 = 0 0 1 1 *
@monthly # 每月执行 = 0 0 1 * *
@weekly # 每周执行 = 0 0 * * 0
@daily # 每天执行 = 0 0 * * *
@hourly # 每小时执行 = 0 * * * *
# 使用示例
@reboot /opt/myapp/start.sh
@daily /usr/local/bin/daily-backup.shcron 实用技巧
环境变量
cron 运行环境与用户 Shell 环境不同,PATH 等变量可能不完整:
# 在 crontab 顶部设置环境变量
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=admin@example.com
# 或在命令中使用完整路径
0 3 * * * /usr/bin/rsync -av /source/ /backup/日志记录
# 将输出重定向到日志文件
0 3 * * * /path/to/script.sh >> /var/log/myscript.log 2>&1
# 丢弃所有输出
0 3 * * * /path/to/script.sh > /dev/null 2>&1
# 只记录错误
0 3 * * * /path/to/script.sh > /dev/null 2>> /var/log/myscript-error.log邮件通知
# 在 crontab 中设置邮件接收者
MAILTO=admin@example.com
# 禁用邮件通知
MAILTO=""查看 cron 日志
# 通过 journalctl 查看
journalctl -u cron.service
# 或查看 syslog
grep CRON /var/log/syslog系统级 cron 目录
Ubuntu 提供了几个预定义的 cron 目录:
# 将脚本放入相应目录即可自动执行
ls /etc/cron.hourly/ # 每小时
ls /etc/cron.daily/ # 每天
ls /etc/cron.weekly/ # 每周
ls /etc/cron.monthly/ # 每月# 放入脚本并确保有执行权限
sudo cp myscript.sh /etc/cron.daily/
sudo chmod +x /etc/cron.daily/myscript.sh系统级 cron 配置文件 /etc/crontab:
cat /etc/crontabSHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# m h dom mon dow user command
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )systemd timers
systemd timers 是 cron 的现代替代方案,提供了更精确的时间控制和更好的日志支持。
查看现有 timers
# 列出所有活动的 timers
systemctl list-timers --all
# 输出示例:
# NEXT LEFT LAST PASSED UNIT ACTIVATES
# Tue 2026-03-24 06:00:00 CST 2h left Mon 2026-03-23 06:00:00 CST 22h ago apt-daily.timer apt-daily.service创建自定义 timer
创建 timer 需要两个文件:一个 .service 文件和一个 .timer 文件。
步骤 1:创建服务文件
sudo nano /etc/systemd/system/my-backup.service[Unit]
Description=Daily Backup Job
[Service]
Type=oneshot
ExecStart=/usr/local/bin/daily-backup.sh
User=root
StandardOutput=journal
StandardError=journal步骤 2:创建 timer 文件
sudo nano /etc/systemd/system/my-backup.timer[Unit]
Description=Run Daily Backup at 3 AM
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.target步骤 3:启用 timer
sudo systemctl daemon-reload
sudo systemctl enable --now my-backup.timer
# 验证
systemctl list-timers | grep my-backup
# 手动触发一次测试
sudo systemctl start my-backup.service
# 查看执行日志
journalctl -u my-backup.serviceOnCalendar 时间表达式
# 每天 3 点
OnCalendar=*-*-* 03:00:00
# 每周一 9 点
OnCalendar=Mon *-*-* 09:00:00
# 每月 1 号
OnCalendar=*-*-01 00:00:00
# 工作日每天 8 点
OnCalendar=Mon..Fri *-*-* 08:00:00
# 每 15 分钟
OnCalendar=*:0/15
# 每小时
OnCalendar=hourly
# 每天
OnCalendar=daily
# 每周
OnCalendar=weekly验证时间表达式:
# 测试表达式,查看未来的触发时间
systemd-analyze calendar "Mon..Fri *-*-* 08:00:00"
systemd-analyze calendar "*:0/15"基于事件的 timer
除了基于日历时间,还可以基于事件触发:
[Timer]
# 系统启动后 5 分钟执行
OnBootSec=5min
# 上次执行完成后 1 小时再执行
OnUnitActiveSec=1h
# 组合使用
OnBootSec=10min
OnUnitActiveSec=1h瞬时 timer(一次性延时执行)
# 30 分钟后执行一个命令
systemd-run --on-active=30m /usr/local/bin/task.sh
# 在指定时间执行
systemd-run --on-calendar="2026-03-25 10:00:00" /usr/local/bin/task.shcron 与 systemd timers 对比
| 特性 | cron | systemd timers |
|---|---|---|
| 配置复杂度 | 简单,一行搞定 | 需要两个文件 |
| 日志 | 需要手动配置 | 自动集成 journalctl |
| 依赖管理 | 不支持 | 支持服务依赖 |
| 精度 | 最小单位为分钟 | 可以精确到秒 |
| 错过的任务 | 不执行 | Persistent=true 会补执行 |
| 资源控制 | 不支持 | 支持 cgroup 资源限制 |
| 随机延迟 | 不支持 | RandomizedDelaySec |
最佳实践
- 简单定时任务用 cron,复杂的用 systemd timers。
- 始终记录日志,方便排查问题。
- 使用完整路径,避免 PATH 问题。
- 避免任务重叠,长时间运行的任务应加锁:
# 使用 flock 防止任务重叠
* * * * * /usr/bin/flock -n /tmp/myjob.lock /path/to/script.sh- 测试后再部署,先手动执行脚本确认无误。
Last updated on