TOC

Linux 定时任务(cron/crontab)

https://mp.weixin.qq.com/s/EJGz2koxuvLzJhnKXUBiAA

任何一本 Linux 书籍都会讲到 Cron 和 At 两个命令,都是定时执行命令,不同的是 at 执行一次,cron 周期性执行。

我们常见的 cron 应该是有这 3 种:

  • vixie cron
  • 支持 @yearly @monthly 等关键字
  • @reboot 关键字,用于系统启动之后执行
  • 环境变量
  • crontab
  • 邮件通知
  • 日志记录
  • 多任务并发
  • anacron
  • systemd-cron

cron 是一个知名的定时任务服务,大多数 UNIX / Linux 系统都已经预装了。

cron 包包含两个可执行文件:

  • /usr/bin/cron 后台程序(系统服务),定期执行命令或脚本,可精确到分钟
  • /usr/bin/crontab 管理定时任务(增删改查),每个用户都有自己的 crontab 文件

检查是否安装:

which crontab

cron

定时任务定义语法(分时日月周):

* * * * * command to be executed
- - - - -
| | | | |
| | | | ----- Day of the week (0 - 6) (Sunday is both 0 and 7)
| | | ------- Month (1 - 12)
| | --------- Day of the month (1 - 31)
| ----------- Hour (0 - 23)
------------- Minute (0 - 59)

比如:0 23 * * * bash /path/to/backup-script.sh 表示每晚 11 点运行一个备份脚本。

  • , 表示多个值
  • - 表示一个范围
  • / 表示每隔多长时间

问题:cron 只能执行简单任务,不支持交互、错误处理、日志等功能。

crontab

  • crontab -e:编辑
  • crontab -l:列出
  • crontab -r:删除

脚本中可以使用 TZ 指定时区,如下(没用实操过):

TZ=UTC
0 0 * * * /path/to/backup-script.sh

配置文件

在大多数 UNIX 和类 UNIX 系统中,cron 会从多个文件中读取定时任务的配置。这些文件通常包括:

  1. /etc/crontab 系统级,需要指定执行用户
  2. /etc/cron.d/
  3. /var/spool/cron/ 每个用户有一个自己名字的文件

anacron

好像 CentOS 中默认安装的是这货。
和 cron 相比,是基于时间间隔来的,也就是说发现距离上一次执行的时间超过了定义的间隔就再次执行。
cron 是指定到具体的时间点,如果那个时间点系统关机了,这个任务就错误了,不会执行。

提供 anacron,anacrontab 两个命令。

anacron [-s] [-f] [-n] [-d] [-t] [-S] [-T] [-u] [-r] [-V] [job] ...
-s:以非安静模式运行,输出详细信息。
-f:强制运行所有作业,忽略上次运行时间间隔。
-n:以模拟模式运行,输出将要运行的作业信息。
-d:以调试模式运行,输出调试信息。
-t:测试配置文件中所有作业是否可运行。
-S:停止所有正在运行的作业。
-T:将所有正在运行的作业的运行时间戳更新为当前时间。
-u:指定运行作业的用户。
-r:重新载入配置文件。
-V:显示版本信息。
cat /etc/anacrontab
# /etc/anacrontab: configuration file for anacron

# See anacron(8) and anacrontab(5) for details.

SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# the maximal random delay added to the base delay of the jobs
RANDOM_DELAY=45
# the jobs will be started during the following hours only
START_HOURS_RANGE=3-22

#period in days   delay in minutes   job-identifier   command
1       5       cron.daily              nice run-parts /etc/cron.daily
7       25      cron.weekly             nice run-parts /etc/cron.weekly
@monthly 45     cron.monthly            nice run-parts /etc/cron.monthly

systemd-cron

Systemd 这个大管家引入之后,当然定时任务这点小事也可以顺带着就给做了。

采用和系统服务相同格式的 unit file 来声明定时任务,可以定义依赖关系,精度到毫秒。从各方面来看都应该强大得多,但是大多数使用场景下简单的 cron 足够了,所以我还没有使用过 systemd-cron。

systemd-cron 也提供一个 crontab 命令,可以兼容原来的语法。

systemctl list-units | grep cron
  cron.service                                                                                loaded active running   Regular background program processing daemon
  anacron.timer                                                                               loaded active waiting   Trigger anacron every hour

测试

# ll /opt/cron_test.sh /etc/cron.d/test
-rw-r--r-- 1 root root  33 Jun  8 12:53 /etc/cron.d/test
-rwxr-xr-x 1 root root 184 Jun  8 12:52 /opt/cron_test.sh
# cat /etc/cron.d/test
* * * * * root /opt/cron_test.sh
# cat /opt/cron_test.sh
#!/bin/bash

{
    echo "===================="
    echo "TIME: $(date '+%F %T')"
    echo "USER: $(whoami)"
    echo "PWD : $(pwd)"
    echo "PATH: $PATH"
} >> /tmp/cron_test.log 2>&1
# tail -f /tmp/cron_test.log
====================
TIME: 2026-06-08 12:54:01
USER: root
PWD : /root
PATH: /usr/bin:/bin
^C
# journalctl -u cron
-- No entries --
# journalctl -u crond | grep test
Jun 08 12:54:01 iZt4nerpnxvn37c1tlx3brZ CROND[1376687]: (root) CMD (/opt/cron_test.sh)
Jun 08 12:54:01 iZt4nerpnxvn37c1tlx3brZ CROND[1376686]: (root) CMDEND (/opt/cron_test.sh)
Jun 08 12:55:01 iZt4nerpnxvn37c1tlx3brZ CROND[1376701]: (root) CMD (/opt/cron_test.sh)
Jun 08 12:55:01 iZt4nerpnxvn37c1tlx3brZ CROND[1376700]: (root) CMDEND (/opt/cron_test.sh)
Jun 08 12:56:01 iZt4nerpnxvn37c1tlx3brZ CROND[1376711]: (root) CMD (/opt/cron_test.sh)
Jun 08 12:56:01 iZt4nerpnxvn37c1tlx3brZ CROND[1376710]: (root) CMDEND (/opt/cron_test.sh)
Jun 08 12:57:01 iZt4nerpnxvn37c1tlx3brZ CROND[1376750]: (root) CMD (/opt/cron_test.sh)
Jun 08 12:57:01 iZt4nerpnxvn37c1tlx3brZ CROND[1376749]: (root) CMDEND (/opt/cron_test.sh)
如果你有魔法,你可以看到一个评论框~