Linux 下的一次性任务 at、batch 和定时任务 cron、anacron

文章目录

    • 一、 任务分类
    • 二、at 一次性任务
      • 2.1 运行方式
      • 2.2 at 的使用权限
      • 2.3 at语法
      • 2.4 例子
          • 2.4.1 -m
      • 2.5 batch:空闲时运行 at
      • CPU 负载查询 uptime
    • 三、循环任务 crontab
      • 3.1 用户级创建和权限设置
      • 3.2 语法
        • 编辑一个任务
        • 查看任务
        • 删除任务
      • 3.3 系统级cron 任务
        • /etc/crontab
      • 3.4 其他cron 配置
        • /etc/cron.d
    • 四、anacron
      • anacron 执行流程
    • 五、总结
      • at
      • cron

一、 任务分类

Linux 中的定时任务可以分为 at 和 cron 两种。

  • at

    在某个时间仅执行一次

  • crontab

    从名字上看很像我们常用的 cron 表达式,该命令可以指定时间进行周期性执行任务

二、at 一次性任务

at 命令需要启动 atd 服务。

安装

yum -y install at

开机启动和状态查看:

[root@localhost ~]# systemctl enable atd
[root@localhost ~]# systemctl status atd
● atd.service - Job spooling tools
   Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
   Active: active (running) since 四 2021-09-09 20:57:55 CST; 14s ago
 Main PID: 14283 (atd)
   CGroup: /system.slice/atd.service
           └─14283 /usr/sbin/atd -f

9月 09 20:57:55 localhost.localdomain systemd[1]: Started Job spooling tools.
Hint: Some lines were ellipsized, use -l to show in full.

2.1 运行方式

at 命令产生的任务都将以文本文件的方式写入/var/spoll/at目录内,等待 atd 服务的执行。我们创建了 at 任务后,就交给 atd 服务了,其会在后台运行我们的任务。

2.2 at 的使用权限

用户使用 at 的权限受/etc/at.allow/etc/at.deny两个文件限制。

  • 如果at.allow文件存在,则只有文件内的用户可以使用 at 命令,其他用户都不可使用;
  • 如果at.deny文件不存在,则只有at.deny文件中的用户不可使用 at命令,其他用户都可以使用【注意,仅在 at.allow 不存在时, 该文件才生效】

语法结合下面的2.3

示例1:

et.deny中添加用户 xiaoyunshi,然后切换到 xiaoyunshi 用户执行任务,发现没有权限执行:

[root@localhost ~]$ cat /etc/at.deny
xiaoyunshi
[xiaoyunshi@localhost ~]$ at now +1 minutes
You do not have permission to use at.

接着删除 at.deny 文件的 xiaoyunshi,就可以执行了:

[xiaoyunshi@localhost ~]$ at now +1 minutes
at> ls ~
at> <EOT>
job 8 at Thu Sep  9 21:36:00 2021

示例2:

at.allow文件中添加test用户,表明只有 test 可以执行 at 命令【当然 root 也可以】:

# xiaoyunshi 用户又无法执行了
[xiaoyunshi@localhost ~]$ at now +1 minutes
You do not have permission to use at.
[xiaoyunshi@localhost ~]$ exit
登出
# 切换 test 用户
[root@localhost ~]# su - test
# 可以执行
[test@localhost ~]$ at now + 1minutes
at> ls ~
at> <EOT>
job 10 at Thu Sep  9 21:39:00 2021

2.3 at语法

at [参数] 时间

  • -m

    at 执行完毕后,无论有没有标准输出,都会发送邮件给执行者【看下面的例1】

  • -l
    【相当于 atq】

    列出当前系统当前用户的所有 at 任务

    [root@localhost mail]# at -l
    2	Fri Oct  1 10:00:00 2021 a root
    
  • -d + 任务 id

    【相当于 atrw】

    取消一个 at 任务

    [root@localhost mail]# atrm 2
    [root@localhost mail]# atq
    
  • -v

    使用明显的时间格式列出 at 中的任务列表【我没懂】

  • -c + 任务 id

    输出当前任务实际执行的命令内容 【不重要】

时间格式

  • HH:MM

  • HH:MM YYYY-MM-DD

  • HH:MM[ am | pm ] [ Month ] [ Date ]

    如: 11am Obtober 1 10月1日上午11点执行。14:23 July 2:7月2日下午2点23执行

  • HH:MM[ am | pm ] + num [minutes | hours | days | weeks ]

    某个时间点后加一断时间后执行,如:03pm + 3 weeks 当天下午的3点后加3周后执行

可以看到执行的最小单位是分钟,而不像我们其他程序中,可以精确到秒

2.4 例子

2.4.1 -m

1:执行一个1分钟后的任务,列出/root/at_dir目录文件列表,如下,此时没有任何文件:

[root@localhost at_dir]# pwd
/root/at_dir
[root@localhost at_dir]# ll
总用量 0

执行一个 at 任务:

[root@localhost at_dir]# at now + 1 minutes
at> ls /root/at_dir
at> <EOT>
job 3 at Thu Sep  9 21:20:00 2021

在输入完 at 命令后,会进入 at>命令行,此时就可以输入要执行的任务了,如上我是执行了 ls 命令【注意,在 at 中,最后都使用绝对路径,避免出错】,最后ctrl +d 结束输入,就会输出当前的任何信息:

job 3 at Thu Sep 9 21:20:00 2021:任务 id 为3,后面跟执行时刻

但是并没有任何输出,当然,我们没文件嘛,就算输出也看不到,

2:那我们创建一个文件,然后再创建一个 at 任务:

[root@localhost at_dir]# touch hahaha.txt
[root@localhost at_dir]# at now + 1 minutes
at> ls /root/at_dir
at> <EOT>
job 4 at Thu Sep  9 21:22:00 2021

1分钟后,按下任意键【如回车】可以看到以下信息,atd 会将结果以邮件的形式告诉执行者:

您在 /var/spool/mail/root 中有新邮件

查看该文件在最后可以看到如下内容:

# 以下是邮件的相关信息
From [email protected]  Thu Sep  9 21:24:03 2021
Return-Path: <[email protected]>
X-Original-To: root
Delivered-To: [email protected]
Received: by localhost.localdomain (Postfix, from userid 0)
        id 467AD4025FB7; Thu,  9 Sep 2021 21:24:03 +0800 (CST)
Subject: Output from your job        5 # 这里是主题,从id 为5的job中输出的
To: [email protected]
Message-Id: <20210909132403[email protected]>
Date: Thu,  9 Sep 2021 21:24:03 +0800 (CST)
From: [email protected] (root)

hahaha.txt # 这里就是我们 job 的执行结果

3:如果想其没有输出的时候也发送邮件,就可以使用-m 参数:

# 删除对应目录下的文件后再执行以下任务
[root@localhost mail]# at -m now + 1 minutes
at> ls /root/at_dir
at> <EOT>
job 7 at Thu Sep  9 21:31:00 202

这时就可看到邮件了,虽然没有内容:

From [email protected]  Thu Sep  9 21:31:00 2021
Return-Path: <[email protected]>
X-Original-To: root
Delivered-To: [email protected]
Received: by localhost.localdomain (Postfix, from userid 0)
        id 735904025FB6; Thu,  9 Sep 2021 21:31:00 +0800 (CST)
Subject: Output from your job        7 # 来自新建的 job7
To: [email protected]
Message-Id: <20210909133100[email protected]>
Date: Thu,  9 Sep 2021 21:31:00 +0800 (CST)
From: [email protected] (root)

2.5 batch:空闲时运行 at

batch 命令就是使用的 at 命令,只不过 batch 会帮助我们在系统的 CPU 负载低于0.8时才会运行我们的任务,因此也不需要指定时间了。

[root@localhost mail]# batch
at> ls ~
at> <EOT>
job 13 at Thu Sep  9 21:53:00 2021

这里的例子都寄件非常简单,重点在于 at 命令的使用

CPU 负载查询 uptime

[root@localhost mail]# uptime
 21:55:36 up 4 days, 15:19,  1 user,  load average: 0.00, 0.01, 0.05

后面的三个数据分别代表1分钟、5分钟和15分钟的平均负载

三、循环任务 crontab

由 crond 服务提供,也是基于 cron 表达式,只不过 Linux 中最小支持分钟,最大支持周。

3.1 用户级创建和权限设置

同 at 一样,提供了如下两个文件:

  • /etc/cron.allow
  • /etc/cron.deny

用户xxx执行 crontab 建立任务后,任务记录到/var/spool/cron/xxx目录中,因此这种方式针对用户来创建任务的。

任务日志会被记录到/var/log/cron

3.2 语法

crontab [-u username] [ -l | -e | -r ]

  • -u

    该参数只有 root 可以使用,帮助 username 创建某个任务

  • -l

    查看 crontab 内容

  • -e

    编辑任务内容【可以看到所有已编辑任务,因此如果要删除某个任务的话,可以直接通过-e 手动删除】

  • -r

    删除所有 crontab 任务内容

任务编辑格式:

* * * * 执行的任务

前面4个星号其实就是 cron 表达式,其取值按顺序分别如下:

  • 分钟

    0~59

  • 小时

    0~23

  • 日期

    1~31

  • 1~12

  • 0~7

特殊符号

    任何。如0 12 * * * 就代表每天的12点0分执行。因为只限定了小时和分钟,日期和月都没有限制

  • ,

    分隔时间。如,每天12点、12点05、12点10分执行:0,5,10 12 * * *

    时间段。

    如:每天8点到12点的整点执行一次:0 8-12 * * *

  • /n

    每隔 n 单位执行一次。

    如每5分钟执行一次:*/5 * * * *

    每12小时执行一次: 0 */12 * * *

编辑一个任务

切换到 xiaoyunshi 用户然后执行以下命令,进入vi模式的任务编辑:

[xiaoyunshi@localhost ~]$ crontab -e
*/1 * * * * date 

如上任务很简单,每分钟执行一次 date 命令,这时我们就可以在/var/spool/cron/xiaoyunshi中收到任务执行的结果邮件:

Return-Path: <[email protected]>
X-Original-To: xiaoyunshi
Delivered-To: [email protected]
Received: by localhost.localdomain (Postfix, from userid 1000)
        id DD60A4025FB9; Sat, 11 Sep 2021 10:18:01 +0800 (CST)
From: "(Cron Daemon)" <[email protected]>
To: [email protected]
Subject: Cron <xiaoyunshi@localhost> date
Content-Type: text/plain; charset=UTF-8
Auto-Submitted: auto-generated
Precedence: bulk
X-Cron-Env: <XDG_SESSION_ID=4>
X-Cron-Env: <XDG_RUNTIME_DIR=/run/user/1000>
X-Cron-Env: <LANG=zh_CN.UTF-8>
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/home/xiaoyunshi>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=xiaoyunshi>
X-Cron-Env: <USER=xiaoyunshi>
Message-Id: <20210911021801[email protected]>
Date: Sat, 11 Sep 2021 10:18:01 +0800 (CST)

2021年 09月 11日 星期六 10:18:01 CST

查看任务
[xiaoyunshi@localhost ~]$ crontab -l
*/1 * * * * date
删除任务
[xiaoyunshi@localhost ~]$ crontab -r
# 再次查看,已经没有任何任务了
[xiaoyunshi@localhost ~]$ crontab -l
no crontab for xiaoyunshi

一定要注意,-r 是删除所有任务

3.3 系统级cron 任务

如果要创建系统维护相关的任务,则需要在/etc/crontab文件中进行任务编辑。

crond 服务会每分钟读取一次/etc/crontab文件中的任务和刚刚的用户创建的任务文件内容:/var/spool/cron/xxx

如果编辑完/etc/crontab文件后任务没有执行,则可能该系统是先读取到内存中的,因此要重新启动下 crond 服务。

/etc/crontab

该文件内容如下:

SHELL=/bin/bash # 使用的 shell
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 

* * * * * user-name command to be executed,这个是该文件的任务创建语法。

crontab -e的方式多了个 user-name 参数,因为该文件一般是由 root 来创建系统任务的嘛,因此创建的任务需要指定任务的执行者是谁,而crontab -e默认的执行者就是当前用户,因此不需要该参数。

每个任务在此编辑即可,这里就不演示了,方法和 crontab -e 一样。

3.4 其他cron 配置

/etc/cron.d

该目录主要用于配置一些自己开发软件时需要用的任务。

默认有一个0hourly文件:

# Run the hourly jobs
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
01 * * * * root run-parts /etc/cron.hourly

该文件内容主要执行最后的命令:每分钟调用一次run-parts脚本来执行/etc/cron.hourly目录下的任务。

run-parts是一个脚本,会在5分钟内随机选一个时间来执行/etc/cron.hourly目录下的执行文件

[root@localhost cron.d]# whereis run-parts
run-parts: /usr/bin/run-parts

接着看一下/etc 下和 cron 有关的目录:

[root@localhost etc]# ls /cron
cron.d/       cron.deny     cron.monthly/ cron.weekly/
cron.daily/   cron.hourly/  crontab

除了 crontabcron.d外还针对小时、天、周和月分别维护了对应的目录。

其中cron.hourly下的执行文件就由上面的 run-parts 会在每小时的1-5分钟内调用,因此我们可以直接将每小时要执行的命令脚本写在该目录下。

其他几个目录是由 anacron执行。

四、anacron

主要用于执行一些由于关机而无法执行的任务以及某些特殊原因导致没有在指定时间执行的任务。

anacron 是一个程序,会每小时执行一次,因此其配置文件就在/etc/cron.hourly/0anacron中:

#!/bin/sh
# Check whether 0anacron was run today already
if test -r /var/spool/anacron/cron.daily; then
    day=`cat /var/spool/anacron/cron.daily`
fi
if [ `date +%Y%m%d` = "$day" ]; then
    exit 0;
fi

# Do not run jobs when on battery power
if test -x /usr/bin/on_ac_power; then
    /usr/bin/on_ac_power >/dev/null 2>&1
    if test $? -eq 1; then
    exit 0
    fi
fi
/usr/sbin/anacron -s

前面都是校验上一次执行 anacron 的时间戳,在最后执行了anacron -s命令。

语法:

anacron -[sfn] [jobname]

  • -s

    根据时间记录文件的时间戳判断是否需要执行各个 jobname

  • -f

    强制执行,不看时间戳

  • -n

    理科执行未执行的任务,不按延迟时间等待

  • job

    /etc/anacrontab定义的任务名

    因此,anacrontab 的执行,是根据/etc/anacrontab文件的配置来的:

    
    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 # 随机设置最大的延迟时间(min)
    # 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
    #相差的天数  # 延迟时间  # 任务名               # 执行的命令
    

    天数和/var/spool/anacron目录记录的时间戳有关:

    [root@localhost anacron]# ll /var/spool/anacron/
    总用量 12
    -rw-------. 1 root root 9 911 11:41 cron.daily
    -rw-------. 1 root root 9 822 10:59 cron.monthly
    -rw-------. 1 root root 9 99 21:38 cron.weekly
    [root@localhost anacron]# cat cron.daily
    20210911
    

    这三个文件记录了对应目录最近一次执行 anacron 的时间,如 cron.daily 上次执行 anacron 的时间为20210911.

    因此 anacron 执行流程如下:

anacron 执行流程

以 daily 为例。

  • /etc/anacrontab中知道cron.daily如果与上次执行 anacron 时间相差一天及以上,则执行run-parts /etc/cron.daily
  • 查看/var/spool/anacron/cron.daily记录的时间戳和当前时间比较,如果相差超过1天,就执行后面的命令,否则不执行
  • 执行命令时,要根据配置,延迟5+3h 执行

五、总结

at

  • at 用于执行一次性任务
  • 通过/etc/at.allow/etc/at.deny两个文件控制 at 使用权限
  • batch 支持在空闲时执行对应的 at 任务

cron

  • 定时执行任务
  • 通过/etc/cron.allow/etc/cron.deny两个文件控制 at 使用权限;
  • 用户通过crontab -e创建任务,创建的任务记录在/var/spool/cron/用户名文件中;
  • 系统维护相关任务一般在/etc/crontab文件中创建,语法为* * * * * 执行者 执行的命令;
  • 自己软件的任务一般在/etc/cron.d目录创建,语法同上;
  • /etc 下提供了按小时、日、周、月的执行的目录,可将可执行的命令文件直接放在对应目录下;
  • /etc/cron.hourly/下的任务由/etc/cron.d/0hourly执行;
  • /etc下其他周期目录由 anacron 程序调用,anacron 用于执行由于关机和其他原因未按时执行的任务;
  • anacron 每小时被/etc/cron.hourly/0anacron调用,通过/etc/anacrontab配置文件,结合/var/spool/anacron/目录下对应的时间戳文件判断某个任务是否进行调用
  • 因此,/etc/crontab中创建的任务,如果因为关机或其他原因没有按时执行,则就不会再执行了,而/etc/cron.daily/etc/cron.weekly/etc/cron.monthly中超时的任务就可以通过 anacron 程序在下次开机时重新调用。

你可能感兴趣的:(linux,linux,batch,运维,cron)