systemd timer 与 cron 的核心区别在于更精确(秒级)和更可控(支持唤醒触发、服务依赖、休眠补偿);每30秒执行需用 OnUnitActiveSec=30 和 AccuracySec=1s;唤醒后运行需 OnBootSec+OnUnitActiveSec 或监听 sleep.target。

Systemd timer 和 cron 的核心区别在哪
不是“更灵活”,而是“更精确+更可控”。cron 按分钟粒度触发,且不感知系统休眠或服务状态;systemd timer 支持秒级精度、能响应系统启动/唤醒事件、可绑定服务单元依赖关系,还能自动跳过因关机错过的任务(通过 Persistent=true)。
但代价是:它必须和一个 .service 单元配对使用,不能像 cron 那样直接写命令行。
怎么写一个每 30 秒执行一次的 timer
注意:这不是推荐做法(频繁轮询会加重 systemd 负担),但能验证秒级能力。关键点在于 timer 文件里用 OnUnitActiveSec 或 OnUnitInactiveSec,而不是 OnCalendar。
- 新建
/etc/systemd/system/myjob.service:[Unit] Description=My periodic job <p>[Service] Type=oneshot ExecStart=/usr/local/bin/my-script.sh</p>
- 新建
/etc/systemd/system/myjob.timer:[Unit] Description=Run myjob every 30 seconds <p>[Timer] OnUnitActiveSec=30 AccuracySec=1s Persistent=false</p><p>[Install] WantedBy=timers.target</p>
- 启用并启动:
systemctl daemon-reload→systemctl enable --now myjob.timer
AccuracySec=1s 很重要,默认是 60s,否则 systemd 可能批量合并多个 30s 任务;Persistent=false 表示不补漏——如果机器关机了 5 分钟,开机后不会一口气跑 10 次。
怎么让任务在系统唤醒后立刻运行(比如笔记本合盖再打开)
这是 cron 完全做不到的场景。systemd timer 用 OnBootSec + OnUnitActiveSec 组合,再配合 WakeSystem=true(需 root 权限且内核支持)即可响应唤醒事件。
- 在 timer 文件中添加:
[Timer] OnBootSec=5min OnUnitActiveSec=1h WakeSystem=true
-
WakeSystem=true会让 systemd 在系统从 suspend/resume 后主动触发 timer(需硬件和内核支持,不是所有设备都生效) - 更稳妥的做法是监听
systemd-suspend.service的结束事件,用After=systemd-suspend.service+WantedBy=sleep.target实现唤醒后执行
别指望 OnCalendar=*-*-* *:*:00 这种写法能捕获唤醒时刻——它只按墙钟时间走,休眠期间不计时。
为什么 timer 启用了却没运行?常见排查点
systemd timer 的静默失败比 cron 更难察觉,日志分散在多个地方。
- 先确认 timer 是否真正激活:
systemctl list-timers --all—— 注意看 “NEXT” 和 “LEFT” 列,若显示n/a说明未加载或被 disable - 检查 service 单元是否语法合法:
systemctl cat myjob.service看有没有拼写错误,Type=oneshot必须配ExecStart,不能漏 - timer 触发后 service 失败,不会自动重试,也不会报错到 timer 日志里:
journalctl -u myjob.service -n 20才能看到真实退出码 - 权限问题:timer 默认以 root 运行,若脚本需要用户环境(如
$HOME、dbus session),得显式指定User=xxx并加Environment=DISPLAY=:0等
最常被忽略的是:timer 文件名必须和 service 文件名完全一致(不含扩展名),myjob.timer 对应 myjob.service,错一个字母就毫无反应。


















