Skip to content
VDS · 应用与机器人

计划任务:cron 与 systemd 定时器

如何运行计划任务,为什么任务手动执行正常但在 cron 中却毫无动静,以及何时改用 systemd 定时器。

更新于 2026年8月23日

备份、证书续期、临时文件清理、夜间报告——这些都是计划任务。在 Linux 上,有两种方式可以解决:经典的 cron 和 systemd 定时器。

Cron:快速上手

您可以这样编辑某个用户的计划:

crontab -e
crontab -l

每行的格式是五个字段加一条命令:

# min  hour  day  month  day-of-week  command
  0    4    *     *      *            /usr/local/bin/backup.sh
  */15 *    *     *      *            /usr/local/bin/check.sh
  30   3    *     *      0            /usr/bin/systemctl restart myapp

实用快捷方式:@daily、@hourly、@reboot。要检查任务是否真的执行过:

grep CRON /var/log/syslog | tail -30
journalctl -u cron --since "1 hour ago"

为什么脚本手动能跑,在 cron 里却不行

这是最常见的问题,原因几乎总是以下三种之一。

环境不同。 Cron 的 PATH 极简,也拿不到您 .bashrc 里的任何变量。请使用程序的完整路径,并在脚本开头或 crontab 中显式设置变量:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

目录不同。 任务从用户的主目录启动,因此相对路径会指向别处。请始终使用绝对路径。

输出无处可去。 出错了,但没人看到。请写日志:

0 4 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

还有两个小细节:cron 行中的 % 字符必须转义为 \%,并且 crontab 文件必须以换行符结尾——否则最后一条任务会被忽略。

您需要从外部验证任务是否执行过。静默的 cron 和成功的 cron 看起来一模一样。在 Uptime Kuma 中设置推送检查:脚本在结束时 ping 一个地址,如果一天都没有 ping,您就会收到告警。

systemd 定时器

当任务比单条命令更复杂时,定时器更方便:它有日志、依赖关系、资源限制,还能防止同时运行两份副本。

# /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
# /etc/systemd/system/backup.timer
[Unit]
Description=Run nightly backup

[Timer]
OnCalendar=*-*-* 04:00:00
Persistent=true
RandomizedDelaySec=15m

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers
journalctl -u backup.service -n 50

Persistent=true 会在机器关机期间错过运行时补跑——cron 做不到这一点。RandomizedDelaySec 可以分散负载,避免十几个任务在同一秒启动。

需要注意的事项

  • 机器时间默认是 UTC。在设置“凌晨 4 点”之前,请先检查 timedatectl。
  • 繁重任务(归档、备份校验)受磁盘性能限制。请参阅磁盘速度,并将它们安排在夜间执行。
  • 每五分钟运行一次的长任务会与自身重叠。在 systemd 中,Type=oneshot 有帮助;在 cron 中,请通过 flock 加锁:
*/5 * * * * /usr/bin/flock -n /tmp/job.lock /usr/local/bin/job.sh