用systemd timer配置系统级定时任务更可靠,需成对编写同名.service和.timer文件,置于/etc/systemd/system/下;.service定义执行内容(type=oneshot、绝对路径execstart、建议指定user),.timer定义触发时机(oncalendar支持自然语言格式如“mon 09:00:00”或daily等预设值,persistent=true可补执行但需脚本幂等);启用前必须daemon-reload,启动timer后用journalctl查service日志验证执行。

直接用 systemd timer 配置系统级定时任务,比改 /etc/crontab 更可靠,也比用户级 crontab -e 更适合需要 root 权限、依赖网络或服务状态的任务——但前提是你的发行版用的是 systemd(CentOS 7+、Ubuntu 16.04+、Debian 8+ 等基本都满足)。
怎么写 .service 和 .timer 两个文件
必须成对存在,名字一致(如 backup.service 和 backup.timer),放在 /etc/systemd/system/ 下。缺一不可,且 .timer 里必须通过 Unit=xxx.service 明确关联。
-
.service文件定义“做什么”:用Type=oneshot(执行完就退出)最常见;ExecStart必须是绝对路径命令;建议加User=指定非 root 用户执行,避免权限过大 -
.timer文件定义“什么时候做”:关键字段是[Timer]节下的OnCalendar=(日历时间)或OnBootSec=(启动后多久);Persistent=true很重要——系统关机错过任务时,下次开机自动补执行 - 别漏掉
[Install]节的WantedBy=timers.target,否则systemctl enable会失败
OnCalendar 时间表达式怎么写才不踩坑
OnCalendar 看似像 cron,但语法更接近自然语言,而且默认不支持 cron 风格的 */5 这类步进写法——它只认完整时间点或预设关键词。
- 每天凌晨 2:30 执行:
OnCalendar=*-*-* 02:30:00(注意空格,不是冒号分隔) - 每周一早上 9 点:
OnCalendar=Mon *-*-* 09:00:00或更简洁的OnCalendar=Mon 09:00:00 - 用预设值更安全:
OnCalendar=daily(等价于*-*-* 00:00:00),hourly、weekly也同理 - 验证写法是否合法:运行
systemd-analyze calendar "daily"或systemd-analyze calendar "Mon 09:00",它会告诉你解析结果和下次触发时间
启用后为什么没执行?检查这三步
配置完常遇到“写了、启了、就是不跑”,大概率卡在这几个环节:
- 没重载配置:
sudo systemctl daemon-reload必须执行,否则 systemd 完全不读新文件 - timer 没真正启动:
sudo systemctl start backup.timer(enable 只是开机自启,不等于现在就运行) - service 执行失败被静默吞掉:用
journalctl -u backup.service -n 20 -f查日志,而不是看systemctl status backup.timer——后者只显示 timer 状态,不反映 service 是否成功运行 - 额外提醒:如果脚本里用了环境变量(如
$HOME),.service中要显式声明Environment=HOME=/root,systemd 不继承 shell 环境
真正麻烦的不是写法,而是 Persistent=true 和 OnCalendar 的组合行为——它会让系统在重启后疯狂补任务,如果原脚本没做幂等处理(比如重复备份覆盖),反而引发数据问题。这点比 crontab 更隐蔽,也更需要你在 service 逻辑里自己兜底。











