cron 如何每 5 秒、10 秒或 30 秒运行一次?
cron 最小粒度是 1 分钟,秒级调度要用变通方案:分钟级任务内嵌 sleep 循环、或 systemd timer 的 OnUnitActiveSec;附完整脚本示例与 FAQ。
cron 原生做不到——它每分钟才扫一次 crontab,最小调度粒度就是 1 分钟。 秒级需求的标准变通是:让 cron 每分钟启动一个脚本,脚本内部用 sleep 循环按 N 秒间隔多次执行。
方案一:sleep 循环(最常用)
每 5 秒一次——脚本版(script.sh):
#!/bin/bash
i=0
while [ $i -lt 12 ]; do # 1 分钟 = 12 个 5 秒间隔
/command/to/run &
sleep 5
i=$(( i + 1 ))
done
crontab 里每分钟拉起这个脚本:
* * * * * /path/to/script.sh
每 10 秒:循环 6 次、sleep 10;每 30 秒:循环 2 次、sleep 30。
要点:
- 命令后加
&后台执行,避免命令本身的耗时把间隔拖歪。 - 若命令耗时不稳定,宁可让循环次数略少于理论值,防止脚本跨过整分钟与下一轮 cron 实例重叠(或用
flock防重入)。
方案二:systemd timer(更干净)
秒级调度其实是 systemd timer 的强项:
# /etc/systemd/system/myjob.timer
[Timer]
OnBootSec=1min
OnUnitActiveSec=10s
[Install]
WantedBy=timers.target
# /etc/systemd/system/myjob.service
[Service]
Type=oneshot
ExecStart=/path/to/command
systemctl enable --now myjob.timer 后每 10 秒触发一次,日志直接进 journal,比 sleep 循环可靠、可观测性好得多。
观察任务时应同时记录计划时间、开始时间、结束时间和执行结果。统计某个窗口内的日志总数只能发现数量变化,不能证明每一轮都执行;逐轮核对应使用任务序号或计划时间。 若这些记录已采集到观测云,可用日志检测观察窗口内的成功数与错误数,并按执行周期选择检测频率;需要识别具体漏掉哪一轮时,仍须查询对应的任务序号。
先想清楚:真的需要秒级吗?
每 5 秒执行一次往往意味着应该换个工具:
- 需要持续运行的采集/消费任务 → 写成常驻进程(systemd service 带
Restart=always)。 - 事件驱动 → 消息队列、inotify 之类,而不是轮询。
常见问题(FAQ)
Q:cron 表达式支持秒字段吗?
A:标准 Vixie cron 不支持(五字段,最小分钟)。某些扩展实现(Quartz、Spring 的 cron、部分容器调度器)有六字段含秒的格式,但那不是系统 crontab。
Q:sleep 循环里命令执行超过间隔会怎样?
A:如果命令加了 &,下一轮照常启动,会出现并发实例;不加 &,间隔会被拉长。两种情况都可能踩坑,重要任务建议上 systemd timer。
Q:多个秒级任务会互相干扰吗?
A:会。每分钟的 cron 实例叠加上一轮未结束的进程,负载可能雪崩。同一台机器上的秒级任务尽量合并到一个脚本里串行调度。