crond 定时任务调度

警告
本文最后更新于 2023-10-23,文中内容可能已过时。

crond 定时任务调度

crontab cron table

Linux crontab 是用来定期执行程序的命令。当安装完成操作系统之后,默认便会启动此任务调度命令。crond命令每分钟(这是定时配置的最小粒度)会定期检查是否有要执行的工作,如果有要执行的工作便会自动执行该工作。我通过crontab -e新建了定时任务之后在下一分钟 0 秒就开始执行了。有的 Linux 发行版crontab是读入到内存中的,所以编辑文件后,并不会立即生效,这时候至少要过 2 分钟后才可以,当然你可以重启 cron 来马上执行(service crond restart或者使用systemctl restart crond)。

而 linux 任务调度的工作主要分为以下两类:

  • 系统执行的工作:系统周期性所要执行的工作,如病毒扫描,备份系统数据、清理缓存。指的是 /etc/crontab/etc/cron.d/

  • 个人执行的工作:某个用户定期要做的工作,例如 mysql 数据备份,或者每隔 10 分钟检查邮件服务器是否有新邮件,这些工作可由每个用户自行设置。指的是/var/spool/cron/$USER

1
2
crontab [ -u user ] file
crontab [ -u user ] [ -l | -r | -e ]

说明:

crontab是用来让使用者在固定时间或固定间隔执行程序之用,换句话说,也就是类似使用者的时程表 cron table。(其实时间表达式类似一个正则,当前的时间如果符合这个正则,则会执行特定的程序)

参数说明:

  • -u user是指设定指定 user 的时程表,这个前提是你必须要有其权限 (比如说是 root) 才能够指定他人的时程表。如果不使用 -u user 的话,就是表示设定自己的时程表。事实上只有 root 才能使用此参数,root 通过使用此参数帮其他使用者建立/移除 crontab 工作排程

  • -e :执行文字编辑器来设定时程表,内定的文字编辑器是 VI,如果你想用别的文字编辑器,则请先设定 VISUAL 环境变数来指定使用那个文字编辑器 (比如说 setenv VISUAL joe),一般也都是通过这个来编辑 crontab

  • -r:删除目前的时程表

  • -l:列出目前的时程表

-l -r -e 不能同时使用,从功能上来说就可以猜到不能同时使用

编辑定时任务

执行crontab -e,然后输入定时任务配置即时间 + 程序,比如:

* * * * * date

意思是每分钟输出一次时间,然后保存退出。编辑完,保存之后就立即生效了,注意:定时任务里的程序执行的结果(即默认输出到标准输出的内容)是不会直接显示在终端中,而是把输出到标准输出的内容以邮件的形式发送到/var/spool/mail/$USER文件中(在我这就是/var/spool/mail/lk,注意,这是个文件,不是文件夹),收到邮寄的提醒也不会自动出现在终端,而是在终端运行命令的时候(也就是输出标准输出的时候)带出来,感觉是把邮件提醒追加到了标准输出的后面,输出标准输出的时候才会带出来。

如果你不希望收到这样的邮件,就把执行结果重定向到别的地方,比如在每一行空一格之后加上 > /dev/null 2>&1 (这个语句的含义我们已经在《Linux 文件系统基础》的/dev/null文件小节中解释过)比如

* * * * * date > /dev/null 2>&1

当然你可以可把执行结果重定向到别的文件中,

* * * * * date >> /tmp/crondate.txt

没有邮件了,自然就不会有邮件提醒


你也可以把时间 + 命令的配置写到文件里,一行一条,然后通过crontab来调用,调用之后就立即生效了,

crontab cronfile.txt

注意,这个时候,crontab之前的配置就被覆盖了,而且没有参数可以修改为追加。不过通过 crontab cronfile.txt 写入的定时任务配置,通过 crontab -e 是可以继续编辑的,那如果我想实现追加的效果怎么办呢,很简单,把命令行放到 sh 文件中,比如~/cronfile.sh,赋予执行权限,然后在 crontab -e 中加一行,调用 cronfile.sh 脚本即可,秒啊!

* * * * * sh ~/cronfile.sh > /dev/null 2>&1


如果出现程序单独可以执行,但是配合写到定时任务里就是无法执行(这种情况有时候会出现,有时候不会出现,很玄学,出现这种情况的一般都是脚本),这主要是因为无法读取环境变量的原因。解决办法:

关于不同的 Bash 进程的配置文件的加载,请看《Bash 启动时的配置文件加载》

  • 所有命令需要写成绝对路径形式,操作的文件也要写成绝对路径,比如ls 要写成 /bin/ls,连执行脚本的 sh 都要写成/bin/sh,如果不知道某个命令的路径可以用which命令(请查看《which》)。例如:

    * * * * * /bin/ls /root >> /tmp/rootfiles.txt

    否则会报找不到名字的错 (/bin/ls) ERROR (getpwnam() failed),

    但是我发现 datecal 不用写绝对路径,这应该是环境变量的原因,因为当前执行环境未加载环境变量。

    在命令前加上. /etc/profile; 命令就不用写绝对路径了,参考最后一点,例如:

    * * * * * . /etc/profile; ls >> /tmp/crondate.txt

  • 在 shell 脚本开头使用以下代码,注意 ./etc之间有一个空格,.~/.bash之间有一个空格

    1
    2
    3
    
    #!/bin/sh
    . /etc/profile
    . ~/.bash_profile
  • /etc/crontab 文件中添加环境变量,即在文件的 PATH 属性中添加路径

    在可执行命令之前添加命令. /etc/profile;使得环境变量生效。分号表示一行执行多个命令的时候用英文逗号分开,例如:

    20 03 * * * . /etc/profile;/bin/sh /var/www/runoob/test.sh

定时时间配置

CRON 表达式校验网址:crontab guru

配置定时任务的时候最重要的就是时间部分的配置

时间格式如下:口诀是 分时日月周

1
2
3
4
5
6
7
8
f1   f2   f3   f4   f5   program
*    *    *    *    *
|    |     |    |     |
|    |     |    |     +----- 星期中星期几 (0 - 6) (星期天 为0),或者直接写sun , mon , tue , wed , thu , fri , sat
|    |     |    +---------- 月份 (1 - 12) 或者直接写 jan , feb , mar , apr  ...
|    |     +--------------- 日期,一个月中的第几天 (1 - 31)
|    +-------------------- 小时 (0 - 23)
+------------------------- 分钟 (0 - 59)  

其中 f1 是表示分钟,f2 表示小时,f3 表示一个月份中的第几日,f4 表示月份,f5 表示一个星期中的第几天。program 表示要执行的程序。

  • 当 f1 为 * 时表示每分钟都要执行 program,f2 为 * 时表示每小时都要执行程序,其余类推

  • 当 f1 为 a-b 时表示从第 a 分钟到第 b 分钟这段时间内要执行,f2 为 a-b 时表示从第 a 到第 b 小时都要执行,其余类推

  • 当 f1 为 */n 时表示每 n 分钟个时间间隔执行一次,f2 为 */n 表示每 n 小时个时间间隔执行一次,其余类推

  • 当 f1 为 a, b, c,... 时表示第 a, b, c,… 分钟要执行,f2 为 a, b, c,... 时表示第 a, b, c…个小时要执行,其余类推

  • a-b/n可以组合使用a-b/n,意思是 a-b 的时间段内每隔 n 分钟(f1)运行一次,

  • ,号两端可以写数字,也可以写 a-b,也可以写*/n(但是不建议,会重复),也可以写a-b/n,逗号将他们连在一起,表示或的关系,满足其中一段即可

  • f3 和 f5 都是指天,同时指定的时候是怎么处理的呢?

    • 当日期、星期都是数值(非*的值)时,满足 || 关系,即满足任何一个就生效;

    • 当日期、星期中,有一个是数值,另一个是*值时,数值生效,而*值不生效;

    • 当然当日期、星期都是*值时,指每一天都生效,就不用纠结到底是谁生效。

简单实践:

1-10/2 * * * *:从第 1 分钟到第 10 分钟,每两分钟执行一次

1-10/2,20,30-40 * * * *:从第 1 分钟到第 10 分钟,每两分钟执行一次,同时第 20 分钟执行一次,第 30-40 分钟一直执行(每分钟执行一次)

cron 和 crond、crontab

cron是 Linux 内置计划任务服务的名称,crond是这个服务的进程名称,crontab是用来创建定时任务的命令,你可以把crontab编辑的文件看作是cron的配置文件,也可以叫它作业列表。

核心配置文件

涉及到的文件:

  • /etc/crontab 文件

    系统性任务的定时列表,负责调度各种管理和维护任务。

    f1 f2 f3 f4 f5 program的解释一模一样,只是多了个 user,command to be executed 的书写规则和问题同 crontab -e 中 program,只有 root 用户能用可以编辑此文件。

  • /etc/cron.d/ 文件夹

    存放全局级别的定时任务。全局性的计划任务一般放到这个文件夹下。比如,有些程序需要自己的定时指令,比如定时清理垃圾数据缓存数据之类的,就会把自己的crontab文件(即定时任务配置文件)放在/etc/cron.d/目录下。定时任务配置文件的书写规则和问题同crontab -e 中 program,也需要指定 user。只有 root 用户可以操作此文件。

  • /var/spool/cron/$USER 文件

    用户级别的定时任务,文件名是$USER,每个用户都会在/var/spool/cron下有一个名称为用户名的文件用来存放此用户的定时任务配置文件,包括 root,而用户crontab -e编辑的就是这个文件。

    另外提一句:不要在/var/spool/cron/中手动创建crontab文件,应该使用crontab命令来创建

    虽然当前用户对 /var/spool/cron/$USER 有读写权限

    但是无法进入父目录,所以依然只能通过 root 权限查看

crond进程每分钟会定期检查三个目录或文件中是否有要执行的任务,1 是/etc/crontab,2 是/etc/cron.d目录下的所有文件,3 是每个用户的配置文件,即/var/spool/cron/$USER,如果当前时间跟定时任务配置文件中的时间匹配上了,就会自动执行该任务。因此,计划任务运行的最小时间间隔是 1 分钟,也就是说任务最频繁只能每分钟运行一次。

除了/var/spool/cron/$USER 以外,/etc/crontab/etc/cron.d的定时任务配置文件都要指定执行人 user,其实定时任务都需要要执行人,只是/var/spool/cron/$USER的执行人已经确定是$USER,不需要再手动指定而已,这个执行人的意思是命令由谁来执行,以谁的角色,谁的权限来运行,首先执行人信息在日志记录中就会体现,同时定时任务涉及到的文件和目录的权限问题也会以执行人的权限为参考,如果不指定则会报错。

* * * * * user-name command to be executed

其他文件或者目录

  • /var/log/cron

    日志目录,cron服务执行每一项定时任务的记录和用户使用crontab的操作记录等cron相关的操作都会被记录到/var/log/cron文件中,这个文件只会保存当天的操作日志,之前的日志文件为/var/log/cron-<日期>

    通过这些日志文件,也可以在一定程度上检查一下是否有异常的执行,比如木马定时执行。日志文件只有 root 可以读写

    很详细,日期时间 执行的 session 的信息,执行的命令等。还有 lk 使用 crontab 命令的操作记录

  • /etc/cron.deny 文件和 /etc/cron.allow 文件

    cron.allowcron.deny用来控制哪些用户可以使用crontab命令。格式都是每行一个用户。不允许出现空格。如果文件被修改了,crond不必被重启。每当用户添加或删除一项 cron 任务时这两个文件都会被读取。

    如果用户的名字出现在cron.allow文件中,他就有权使用crontab命令。如果cron.allow文件不存在,系统会检查cron.deny文件来确定是否应该拒绝用户使用crontab命令。如果两个文件都存在,cron.allow有优先权。

    两个文件只使用一个来限制就够了,因此建议只要保留一个即可。一般来说,系统默认是保留/etc/cron.deny如果两个文件都不存在,只有 root 可以提交任务

    如果cron.deny文件为空文件,所有的用户都可以使用crontabcron.deny不能限制 root 用户。此文件只有 root 用户可以读写

    将 lklk 添加到此文件之后

    lklk 用户执行 crontab -e

  • /etc/cron.hourly 文件夹

    放在其中的定时任务配置文件每分钟运行一次

    /etc/cron.d/0hourly文件中,配置的是每个整点 1 分的时候会执行 run-parts /etc/cron.hourly,也就是说 cron.hourly 文件夹,实际上也是在 cron.d 中被调用的,

下面这三个文件夹由 anacron 执行

  • /etc/cron.daily 文件夹,放在其中的定时任务配置文件每天运行一次

  • /etc/cron.weekly 文件夹,放在其中的定时任务配置文件每星期运行一次

  • /etc/cron.monthly 文件夹,放在其中的定时任务配置文件每月运行一次

选用哪种定时任务配置方式最合适

对于普通用户而言,几乎没有权限来操作上面提到的各种文件夹和目录,就算是操作用户自身的定时任务/var/spool/cron/$USER文件,也无法直接编辑,而是需要通过crontab -e命令,所以普通用户只有这一种方式编辑定时任务。

对于 root 用户,有 4 种设置方式编辑定时任务

  1. 命令 crontab -e 内容在文件/var/spool/cron/root

  2. /etc/crontab文件

  3. /etc/cron.d目录下新建一个文件

  4. /etc/cron.daily//etc/cron.hourly//etc/cron.weekly//etc/cron.monthly/

这 4 中应该选哪一种比较好呢?:

先排除 1,2 里面有环境变量,3 里面没有环境变量,2 和 3 格式一样。3 里面文件名字可以自定义,看起来清晰一点,找起来,替换起来很方便,写到 2 里的话还得去找。4 里面,一个目录下如果由多个文件貌似只能使用同一个时间执行。

总之,一般情况下用/etc/cron.d就行了

crond 服务管理

由于 crond 是 Linux 的内置服务,可以用以下的方法启动、关闭这个服务:

service crond status:查看状态

service crond start:启动服务,需要 root 权限

service crond stop:关闭服务,需要 root 权限

service crond restart:重启服务,需要 root 权限

service crond reload:重新载入配置,需要 root 权限

应该注意的问题:

  • crontab%是有特殊含义的,表示换行的意思。如果要用的话必须进行转义\%,如经常用的date '+%Y%m%d'crontab里是不会执行的,应该换成date '+\%Y\%m\%d'

  • 每条 JOB 执行完毕之后,系统会自动将输出发送邮件给当前系统用户。日积月累,非常的多,甚至会撑爆整个系统。所以每条 JOB 命令后面进行重定向处理是非常必要的: >/dev/null 2>&1 。前提是对 Job 中的命令需要正常输出已经作了一定的处理,比如追加到某个特定日志文件。

  • /etc/crontab的权限。不要随意改动这个文件的属性,这个文件属性应该设置成 644 或者 600,否则会报 (system) BAD FILE MODE (/etc/crontab)

0%