Linux 定时单次及周期任务

👌 2021-07-06 Linux 定时单次及周期任务

FileInfo Filename - Linux 定时单次及周期任务 Version - v1.0.2107(2021/07/06 ~ 2021/07/08) Author - nuo standuke Email - shadowdoker@gmail.com DescriptionKey - Linux single scheduled and periodic tasks / at batch cron anacron

版本修订记录:

v1.0.2107:2021-07-06:建立 Linux 定时单次及周期任务 文档,修订人:nuo

[TOC]

适用场景

单次任务

  1. 单一系统更新任务,例如公司产品需要指定时间更新,并且有更新脚本等保障措施,那么可以使用单次任务完成更新操作,同时结合 at 的邮件反馈机制,可以讲更新结果通过邮件告知
  2. 文件有效期,例如某文件在当日某一时刻前可供下载,过后则不允许下载。那么可以通过单次的定时操作,完成文件权限或者删除文件的操作,减少人工介入

周期任务

  1. 定期的日志文件归档、上报「系统运行状态等」
  2. 定期更新本地缓存、例如 locate 数据库信息等
  3. 定期的系统更新或者应用产品更新
  4. 「毒」某些病毒会使用 crond 来检测后台是否在运行,这也是我遇到的一个案例

注意事项

⚠️ 所有的定期任务都是用系统时间,也就是如下输出的 Local time 作为时间标准的。请在使用定期任务时明确当前系统时间。

  >root ~
[vpc]# timedatectl
    Local time: 二 2021-06-29 13:45:54 CST
    Universal time: 二 2021-06-29 05:45:54 UTC
    RTC time: 二 2021-06-29 05:45:54
    Time zone: Asia/Shanghai (CST, +0800)
    NTP enabled: yes
    NTP synchronized: yes
    RTC in local TZ: no
    DST active: n/a

⚠️ 对于 crond 来说

不到三小时的本地时间变化,如夏令时变化引起的时间变化,将会以如下特殊方式处理。这种处理方式只适用于在特定时间「变动的时间区间内」运行的作业,并且时间调整超过一小时,正常调度的任务会被更积极的调度。

  • 如果时间向前调整一小时,那些本应在已跳过的时间间隔内运行的作业将立即运行。相反,如果时间向后调整,则相同任务只会运行一次,将避免运行两次。
  • 超过 3 小时的时间变化被认为是对时钟或时区的更正,会立即使用新的时间。

差异总结

功能差异

  • at:仅执行一次,指定时间节点执行一次,错过后不会再执行
  • batch:仅执行一次,前提是系统负载需要够低,一般是到点且负载低于 0.8 时执行
  • cron:周期性执行,关机时过了时间点的任务不会再执行
  • anacron:执行停机期间错过的工作任务

其他差异

  • 检查频率:at 和 batch 都是计划运行一次,cron 是按 crontab 反复运行,三者在默认情况下都是每分钟检查一次要运行的任务
  • 其他要求:at 和 cron 是到点就触发,batch 是到点且负载值足够低(默认小于0.8)时触发
  • 注:at 和 batch 均由 atd 负责调度(老一些的系统上是 crond 调度 atrun 再处理),cron 由 crond 调度

单次任务 at / batch

应用名:at 服务名:atd 命令行工具:at batch

CentOS 7.9 操作系统中 atbatchman 手册相同

atbatch 从标准输入或指定文件中读取命令,这些命令将在指定时间使用 /bin/sh 执行,在 at 程序下共有如下几个命令

  • at:在指定时间执行命令
  • atq:列出当前用户的待处理作业,超级用户 root 会列出每个人的工作。输出行的格式(每个作业一行):作业号、日期、小时、队列和用户名。
  • atrm:删除由作业编号标识的作业。
  • batch:在系统负载水平允许时批量执行命令;换句话说,当平均负载低于 0.8 或调用 atd 时指定的值时。

介绍

系统 man 手册翻译

at 允许相当复杂的时间规范,扩展了 POSIX.2 标准。它接受 HH:MM 形式的时间以在一天中的特定时间运行作业。「如果时间已经过去,则会使用下一天的那一刻执行。」还可以指定午夜、中午或下午茶时间「下午 4 点」,并且可以设置一个以 AM 或 PM 为后缀的一天中的时间,以便在早上或晚上运行。也可以明确哪一天作业将运行,通过以月份名称日的形式给出一个带有可选年份的日期,或者给出一个形式为 MMDD[CC]YY, MM/DD/[CC]YY, DD.MM.[CC]YY or [CC]YY-MM-DD。规格日期必须遵循一天中的时间规范。还可以给出像 now + count time-units 这样的时间,其中时间单位可以是分钟、小时、天或周,也可以告诉 at 通过在时间后缀今天来运行今天的作业,并通过在时间后缀以明天来运行明天的作业。

例如,要在三天后的下午 4 点运行作业,可以使用 at 4pm + 3 days,在 7 月 31 日上午 10:00 运行作业,可以使用 at 10am Jul 31,然后在明天凌晨 1 点运行,可以使用 at 1am tomorrow

时间规范的定义可以在 /usr/share/doc/at-3.1.13/timespec 中找到。

对于 at 和批处理,从标准输入或使用 -f 选项指定的文件中读取命令并执行。工作目录、环境(变量除外) BASH_VERSINFO、DISPLAY、EUID、GROUPS、SHELLOPTS、TERM、UID 和 _) 和 umask 从调用时起保留。

由于 at 当前作为 setuid 程序实现,因此也不会导出其他环境变量(例如 LD_LIBRARY_PATH 或 LD_PRELOAD)。这在未来可能会改变。作为解决方法,设置这些变量在您的工作中明确显示。

从 su(1) shell 调用的 at - 或批处理 - 命令将保留当前用户 ID。用户将收到来自他的命令的标准错误和标准输出(如果有)。邮件将被发送使用命令 /usr/sbin/sendmail。如果从 su(1) shell 执行 at,登录 shell 的所有者将收到邮件。

超级用户在任何情况下都可以使用这些命令。对于其他用户,使用 at 的权限由文件 /etc/at.allow/etc/at.deny 决定。有关详细信息,请参阅 at.allow(5)。两个文件都存在有 ,则黑名单失效,只有白名单的配置生效。

at 队列存放在 /var/spool/at 目录中,可手动进取看任务、删任务。

安装

yum -y install at
systemctl start atd.service
systemctl enable atd.service

参数

-V 将版本号打印到标准错误并退出。
-q 队列:使用指定的队列。队列名称由单个字母组成,有效的队列指定范围从 a 到 z 和 A 到 Z。a 队列是 at 的默认值,b 队列是 batch 的默认值。具有更高字母的队列有更高的运行优先级。特殊队列 `=` 是为当前正在运行的作业保留的。如果将作业提交到以大写字母指定的队列,则该作业将被视为在作业时提交到 batch 处理。一旦到达时间,batch 程序匹配平均负载的处理规则。如果给 atq 一个特定的队列,它只会显示该队列中待处理的作业。
-m 在作业完成时向用户发送邮件,即使没有输出。
-M 从不向用户发送邮件。
-f file 从文件而不是标准输入读取作业。
-t time 指定作业运行时间,格式为 [[CC]YY]MMDDhhmm[.ss]
-l 是 atq 的别名。
-r 是 atrm 的别名。
-d 是 atrm 的别名。
-b 是 batch 的别名。
-v 显示在读取作业之前将执行作业的时间。显示的时间格式为“Thu Feb 20 14:50:00 1997”。
-c + 作业 id 将命令行上列出的作业转换为标准输出「也就是看这个任务具体的内容」。

示例

  • 定期删除一个文件
[root@localhost.local ~]# at 22:00
at> rm -rf /var/www/html/demo.txt
at> <EOT>
job 2 at Sat Jul  1 22:00:00 201
-----------------------
# 在22:10点
at 22:00

# 删除 /var/www/html/demo.txt 文件
at> rm -rf /var/www/html/demo.txt

# Ctrl+d 结束输入
at> <EOT>

# 提示 第二个任务在 22:00进行
job 2 at Sat Jul  1 22:00:00 201

时间写法与使用案例

# HH:MM
02:00 => 在今日的 02:00 进行,若该时刻已过,则明天此时执行任务

# HH:MM YYYY-MM-DD
02:00 2021-09-20 => 指定 2021 年 9 月 20 日执行任务

# HH:MM[am|pm] [Month] [Date]
04:00 pm March 17 => 指定下一个 3 月 17 日下午 4:00 执行任务
17:20 tomorrow => 明天的 17:20 执行任务

# HH:MM[am|pm] + number [minutes|hours|days|weeks] 在某个时间点再加几个时间后才进行该项任务
now + 5 minutes => 当前时间 5 分钟后执行任务
02 pm + 3 days => 3 天后的下午 2:00 执行任务

batch

batch 用法与 at 一致,两者差异也只有 batch 会考虑系统负载,用的时候把 at 换成 batch 就行了。

周期任务 cron / anacron

cron

应用名:cron 系统服务:crond 命令行工具:crontab crond

介绍

系统 man 手册翻译

Cron 在 /var/spool/cron 中搜索以 /etc/passwd 中的帐户命名的 crontab 文件;找到的 crontab 被加载到内存中。Cron 还搜索 /etc/anacrontab 和任何文件,所以 crontab -e 修改完后需要重启下 crond 服务。但是是否需要重启是看操作系统的,请往下看。

有两种方法可以检查 crontables 中的更改。第一种方法是检查文件的修改时间。第二种方法是使用 inotify 支持。 inotify 的使用记录在守护进程启动后的 /var/log/cron 日志。 inotify 支持检查所有 crontables 中的更改并仅在检测到更改时访问硬盘。使用 modtime 选项时,Cron 每分钟检查其 crontables 的 modtime 以检查任何更改并重新加载已更改的 crontables。之后不需要重启Cron 一些 crontables 被修改。当 inotify 无法初始化时,也会使用 modtime 选项。

Cron 检查这些文件和目录:

  • /etc/crontab

系统 crontab。现在该文件默认为空。最初它通常用于运行每日、每周、每月的工作。默认情况下,这些作业现在通过 anacron 运行,它读取

  • /etc/anacrontab

后面会提到

  • /etc/cron.d/

包含为不同用户存储的系统 cronjobs 的目录。

  • /var/spool/cron

包含由 crontab 命令创建的用户 crontable 的目录。

注意,在 CentOS 7.0+ 系统中只要更改 crontab,crontab 命令就会更新 spool 目录的 modtime。所以就不用重启 crond 服务。

使用

如下为 系统任务 的编写格式,同样适用于所有的 crontab 任务编写。

  >root ~
[node1]# cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name  command to be executed
  • *(星号)

代表任何时刻都接受的意思!举例来说,范例一内那个日、月、周都是 * , 就代表著『不论何月、何日的礼拜几的 12:00 都运行后续命令』的意思!

  • ,(逗号) 代表分隔时段的意思。举例来说,如果要下达的工作是 3:00 与 6:00 时,就会是: 0 3,6 * * * command 时间参数还是有五栏,不过第二栏是 3,6 ,代表 3 与 6 都适用!
  • -(减号) 代表一段时间范围内,举例来说, 8 点到 12 点之间的每小时的 20 分都进行一项工作: 20 8-12 * * * command 仔细看到第二栏变成 8-12 喔!代表 8,9,10,11,12 都适用的意思!
  • /n(斜线) 那个 n 代表数字,亦即是『每隔 n 单位间隔』的意思,例如每五分钟进行一次,则: */5 * * * * command 很简单吧!用 * 与 /5 来搭配,也可以写成 0-59/5 ,相同意思!
普通用户

定时任务文档存放在 /var/spool/cron/demo

crontab -e : 修改定时任务 crontab -l : 查看自己的定时任务 crontab -r : 删除所有定时任务

crontab -u :只有 root 才能进行这个任务,亦即帮其他使用者创建/移除 crontab 工作排程;

系统任务

定时任务文档存放在 /etc/crontab

所有的修改删除等操作,直接编辑任务文档 /etc/crontab 即可,cron 会每分钟去读取一次 /etc/crontab/var/spool/cron 里面的数据内容

anacron

anacron 并不需要额外的配置,使用默认值即可

简介

系统 man 手册翻译 + 互联网资料

Anacron 用于定期执行命令,频率以天为单位。与 cron(8) 不同,它不假设机器连续运行。因此,它可以用于不是一天 24 小时运行的机器来控制日常工作、每周工作和每月工作。

对于每个作业,Anacron 会检查该作业是否在过去 n 天内执行过,其中 n 是为该作业指定的时间段。如果作业在 n 天或更长时间内未执行,则 Anacron 在等待指定为延迟参数的分钟数后运行作业的 shell 命令。命令退出后,Anacron 将日期(不包括小时)记录在该作业的特殊时间戳文件中,因此它知道何时再次执行该作业。

anacron 并不是用来取代 crontab 的,anacron 存在的目的就在於我们上头提到的,在处理非 24 小时一直启动的 Linux 系统的 crontab 的运行!所以 anacron 并不能指定何时运行某项任务, 而是以天为单位或者是在启动后立刻进行 anacron 的动作,他会去侦测停机期间应该进行但是并没有进行的 crontab 任务,并将该任务运行一遍后,anacron 就会自动停止了。

那么 anacron 又是怎么知道我们的系统啥时关机的呢?这就得要使用 anacron 读取的时间记录档 (timestamps) 了! anacron 会去分析现在的时间与时间记录档所记载的上次运行 anacron 的时间,两者比较后若发现有差异,此时 anacron 就会开始运行未进行的 crontab 任务了! 所以 anacron 其实也是透过 crontab 来运行的!因此 anacron 运行的时间通常有两个,一个是系统启动期间运行,一个是写入 crontab 的排程中。

运行原理

anacron 可以理解为一个时间戳工具,判断时间是否连续,如果不连续,那么就执行下中间不连续时间的 cron 工作任务。也就是说 anacron 其实是通过 cron 来运行的,可以在 /etc/cron*/*ana* 内看到,是由 cron 来调用 anacron 来实现的

  >root /etc/cron.d
[node1]# 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
  1. 由 /etc/anacrontab 分析到 cron.daily 这项工作名称的天数为 1 天;
  2. 由 /var/spool/anacron/cron.daily 取出最近一次运行 anacron 的时间戳记;
  3. 由上个步骤与目前的时间比较,若差异天数为 1 天以上 (含 1 天),就准备进行命令;
  4. 若准备进行命令,根据 /etc/anacrontab 的配置,将延迟 5 分钟
  5. 延迟时间过后,开始运行后续命令,亦即『 run-parts /etc/cron.daily 』这串命令;
  6. 运行完毕后, anacron 程序结束。

使用

-f 强制执行所有作业,忽略任何时间戳。
-u 将所有作业的时间戳更新为当前日期,但不运行任何作业。
-s 序列化作业的执行。 Anacron 不会在前一个工作完成之前开始新工作。
-n 立即运行作业并忽略 /etc/anacrontab 文件中的指定延迟。此选项意味着 -s。
-d 不会将 Anacron 分叉到后台。在这种模式下,Anacron 将向标准错误以及系统日志输出信息性消息。任何作业的输出都由 Anacron 邮寄。
-q 将任何消息抑制为标准错误。仅适用于 -d。
-t some_anacrontab 使用指定的 anacrontab,而不是 /etc/anacrontab 默认的。
-T Anacrontab 测试。测试 /etc/anacrontab 配置文件的有效性。如果文件中有错误,它会显示在标准输出中并且 Anacron 返回值 1。有效的 anacrontabs 返回值 0。
-S spooldir 使用指定的 spooldir 来存储时间戳。希望自己运行 anacron 的用户需要此选项。
-V 打印版本信息,然后退出。
-h 打印简短的使用信息,然后退出。

at 与 cron 权限设置

由于两者的权限配置方案极其相似,所以将两者的配置剥离出来放在一起,便于对比。

at

在 CentOS 7.9 系统中,安装完操作系统后默认会有 /etc/at.deny 配置文件,

  • at.deny

在这个 at.deny 文件内的用户则不能使用 at,没有在这个 at.deny 文件中的用户,就可使用 at,

  • at.allow

同样的还有 /etc/at.allow 这个文件,写在这个文件中的使用者才能使用 at ,没有在这个文件中的使用者则不能使用 at (即使没有写在 at.deny 当中)。

如果两个文件都存在,那么依照最小权限,仅 /etc/at.allow 用户可使用 at。 如果两个文件都不存在,那么只有 root 可使用 at。

修改配置的话,里面一行一个用户名即可。

cron

与 at 类似,

在 CentOS 7.9 系统中,安装完操作系统后默认会有 /etc/cron.deny 配置文件,

  • /etc/cron.deny:

在这个 cron.deny 文件内的用户则不能使用 cron,没有在这个 cron.deny 文件中的用户,就可使用 cron,

  • /etc/cron.allow:

同样的还有 /etc/cron.allow 这个文件,写在这个文件中的使用者才能使用 cron ,没有在这个文件中的使用者则不能使用 cron (即使没有写在 cron.deny 当中)。

修改配置的话,里面一行一个用户名即可。

如果两个文件都存在,那么依照最小权限,仅 /etc/cron.allow 用户可使用 cron。 如果两个文件都不存在,那么只有 root 可使用 cron。

demo 用户创建了周期任务,那么 demo 的任务会记录到 /var/spool/cron/demo cron 运行的每一项工作都会被纪录到 /var/log/cron 日志中

写在最后

说实话,这文档写的糟心,一个是网上资料太多,又太乱,没有一个是条理清楚、干干净净的;另一个是没想到有那么多要涉及到的,里面的细节还是非常多的。man 手册帮助挺大的,也总算把这几个定时任务给理了一遍。

参考资料

http://cn.linux.vbird.org/linux_basic/0430cron.php