systemd timers支持“系统空闲时”触发任务,而at命令不支持;推荐使用OnIdleSec=参数配合.timer和.service单元实现原生、高效、无轮询的空闲触发。

Linux 的 at 命令本身不支持“系统空闲时”触发任务——它只按绝对或相对时间调度,不感知 CPU、I/O 或用户活动状态。
换句话说:
✅ at 可以在 明天凌晨2:00、3小时后、下周六14:30 执行命令;
❌ 但不能在 CPU使用率低于5%持续5分钟时、无人操作屏幕10分钟后、磁盘IO空闲时 自动运行。
那“空闲时执行”该怎么做?
你需要组合其他工具来实现逻辑判断,再用 at(或更合适的机制)触发。以下是两种实用方案:
✅ 方案一:用脚本轮询 + at 提前预约(适合轻量、确定性场景)
比如你想“在今晚系统连续空闲15分钟后,运行一次备份”,可以这样:
- 写一个检测空闲的脚本(例如检查
vmstat 1 3的 id 值、或cat /proc/loadavg的1分钟负载); - 如果连续满足空闲条件,就用
at安排立即执行(at now)或稍后执行; - 脚本自身可设为
systemd --on-boot或cron每分钟检查一次。
示例片段(简化版):
# /usr/local/bin/if-idle-then-backup.sh
if awk '{print $15}' <(vmstat 1 3 | tail -1) | grep -q '^[8-9][0-9]\|100$'; then
echo "/usr/local/bin/do-backup.sh" | at now + 1 minute
exit 0
fi⚠️ 注意:
at now实际是“尽快执行”,但受atd队列延迟(通常≤60秒),不是毫秒级响应。
✅ 方案二:用 systemd 的 OnIdleSec=(推荐,更原生可靠)
systemd 提供了真正意义上的空闲检测机制,比轮询更高效、更标准:
# /etc/systemd/system/backup-on-idle.service [Unit] Description=Run backup when system is idle [Service] Type=oneshot ExecStart=/usr/local/bin/do-backup.sh User=root [Install] WantedBy=multi-user.target
# /etc/systemd/system/backup-on-idle.timer [Unit] Description=Trigger backup on idle [Timer] OnIdleSec=900 # 空闲满15分钟才触发 Persistent=false [Install] WantedBy=timers.target
启用它:
sudo systemctl daemon-reload sudo systemctl enable --now backup-on-idle.timer
✅ 这才是真正“空闲时执行”的标准做法:由 systemd 内核级空闲判断(基于 sd_event_source_set_enabled() 和 libsystemd 的 idle logic),无需轮询、无资源浪费。
❌ 为什么不直接用 at 实现空闲触发?
-
atd守护进程只读取时间戳队列,不监控系统状态; - 它的设计目标是“定时”,不是“条件触发”;
- 加入空闲逻辑需改写
atd源码,不现实,也不被上游支持。
小结对比
| 方法 | 是否原生支持空闲 | 是否需轮询 | 是否推荐 | 备注 |
|---|---|---|---|---|
at 命令 |
❌ 否 | ❌ 不适用 | ❌ 不推荐 | 只能定时,不能条件触发 |
轮询脚本 + at
|
⚠️ 间接模拟 | ✅ 是 | ⚠️ 仅临时应急 | 有延迟、耗资源、易误判 |
systemd.timer + OnIdleSec=
|
✅ 是(内核级) | ❌ 否 | ✅ 强烈推荐 | 现代 Linux 标准解法,简洁可靠 |
如果你的系统是较新版本(systemd ≥ v229,即多数 CentOS 8+/Ubuntu 16.04+/Debian 10+),优先用 OnIdleSec=。at 留给明确时间点的任务就好——比如“明早8:00发日报”、“三小时后关机”。


















