linux命令at、crontab、anacron

2018-07-05 17:07:31

延后执行任务

at 命令可以让我们的工作延后在某一特定时刻执行。要支持 at 这个单一工作调度,我么必须要运行 atd 这个服务(一般这个服务都是自动运行了的,如果服务已运行,忽略下面3行)。

yum install at    #安装

systemctl start atd    #运行
systemctl enable atd   #开机自启

事实上,我们使用 at 这个指令来产生所要运行的工作,并将这个工作以文本文件的方式写入 /var/spool/at/ 目录内,该工作便能等待 atd 这个服务的取用与执行了,就这么简单。

对何人能使用 at 命令控制

1.如果有 /etc/at.allow 文件则只有记录在里面的人才能使用at。
2.如果 /etc/at.allow 不存在则查询 /etc/at.deny 文件,记录在 at.deny 中的人不能使用 at。
3.一般的 distribution 都只有 at.deny 文件,这样比较松散,因为这样大部分人都可以使用 at。
4.如果2个文件都不存在,那么只有root才能使用 at。

-l 	相当于 atq,列出目前系统上面的所有该使用者的 at 调度
-c	可以列出后面接的该项工作的实际指令内容
-d	相当于 atrm ,可以取消一个在at调度中的工作
-m	当at的工作完成后,即使没有输出讯息,亦以 email 通知使用者该工作已完成

代表5分钟/小时/天/周后执行
now + 5 minutes/hours/days/weeks

也可以直接指定时间
09:22 2017-01-01

交互式执行 at 命令,<EOT>代表按下 ctrl + d

#1分钟后执行
[root@192 tmp]# at now + 1 minutes
at> ls
at> <EOT>
job 5 at Fri Jul  6 11:44:00 2018
#执行多条指令
at 23:00 2015-08-04
at> ls
at> ls
at> pwd
at> <EOT>

单行命令行执行 at

echo date | at 09:22 2017-10-11

#一分钟后运行
echo '/root/c/a.out' | at now + 1 minutes
[root@192 tmp]# atq
7	Fri Jul  6 11:48:00 2018 a root
[root@192 tmp]# at -l
7	Fri Jul  6 11:48:00 2018 a root
#删除任务
atrm 7

#批量删除任务
atrm `at -l | awk '{print $1}'`

#任务过多推荐使用这种
at -l | awk '{print $1}' | xargs atrm

atd调用程序机制原理

下面我们3个都是1分钟后执行任务,a.out 和 tmp.sh都是非daemon无限睡眠程序。

echo '/root/tmp/a.out' | at now + 1 minutes
echo 'sh /root/tmp/tmp.sh' | at now + 1 minutes
echo '/root/tmp/a.out &' | at now + 1 minutes

1分钟后我们通过执行 ps 得到结果如下。

[root@192 tmp]# ps -ef
...
root      17736    540  0 12:25 ?        00:00:00 /usr/sbin/atd -f
root      17738  17736  0 12:25 ?        00:00:00 sh
root      17739  17738  0 12:25 ?        00:00:00 /bin/bash
root      17740  17739  0 12:25 ?        00:00:00 /root/tmp/a.out

root      17799    540  0 12:34 ?        00:00:00 /usr/sbin/atd -f
root      17801  17799  0 12:34 ?        00:00:00 sh
root      17802  17801  0 12:34 ?        00:00:00 /bin/bash
root      17803  17802  0 12:34 ?        00:00:00 sh /root/tmp/tmp.sh
root      17804  17803  0 12:34 ?        00:00:00 sleep 1000

root      17816      1  0 12:37 ?        00:00:00 /root/tmp/a.out
...

从上面输出我们可以得出以下结论:  

1.每一个通过 at 加入的延时执行任务执行时是通过 atd 服务进程调用 fork() 产生子进程然后进行调用,顺序为 atd - sh - bash - 最后的程序,所以最终会产生 4 个进程。

2.一旦我们这个程序不终止,或者需要很长一段时间终止,那么这4个进程将长时间占用资源,任务一多肯定会造成资源枯竭。

结论:我们通过 at 加进来的程序最好是下面3种程序中的一种:

1.后台daemon程序。
2.运行一次很快会自己终止的程序。
3.运行时加上 & 符号,如 /root/tmp/a.out &


循环执行例行性工作调度

相对于 at 是仅执行一次的工作,循环执行的例行性工作调度则是由 cron (crond) 这个系统服务来控制的。crond 服务和crontab 命令都属于 cronie 软件包,如果系统没带,请自行安装。

crond 调度程序的原理跟 atd 差不多,也是通过fork()来调用程序,所以如果程序需要执行一段时间,最好带上 & 符号挂载后台运行来让 fork() 出来的子进程crond终止来节约资源。比如:

[freecls@192 ~]$ crontab -e
1 * * * * /root/tmp/a.out &

与 at 同样的,我们可以限制使用 crontab 的使用者帐号。

1.如果有 /etc/cron.allow 文件则只有记录在里面的人才能使用 crontab。
2.如果 /etc/cron.allow 不存在则查询 /etc/cron.deny 文件,记录在 cron.deny 中的人不能使用 crontab。
3.一般的 distribution 都只有 cron.deny 文件,这样比较松散,因为这样大部分人都可以使用 crontab。  

当使用者使用 crontab 这个指令来创建工作调度之后,该项工作就会被纪录到 /var/spool/cron/ 里面去了,而且是以帐号来作为判别的!举例来说, freecls 使用 crontab 后, 他的工作会被纪录到 /var/spool/cron/freecls 里头去!但请注意,不要使用 vi 直接编辑该文件, 因为可能由于输入语法错误,会导致无法执行 cron。日志会记录在 /var/log/cron 文件。

[root@study ~]# crontab [-u username] [-l|-e|-r]
选项与参数:
-u :只有 root 才能进行这个任务,亦即帮其他使用者创建/移除 crontab 工作调度;
-e :编辑 crontab 的工作内容
-l :查阅 crontab 的工作内容
-r :移除所有的 crontab 的工作内容,若仅要移除一项,请用 -e 去编辑。
#每天12:00执行程序
[freecls@192 ~]$ crontab -e
#此时会进入vi的编辑画面,一项工作一行。
0 12 * * * ls -l

默认情况下,任何使用者只要不被列入 /etc/cron.deny 当中,那么他就可以直接下达" crontab -e "去编辑自己的例行性命令。

上面 6 个字段的意义为:

分钟 小时  日期月份  周 指令
 0-59 0-23 1-31 1-12 0-7 指令

周的数字0或者7都代表星期天,还有一些辅助字符意思如下:

* 代表任何时刻。
, 逗号代表分隔时段的意思,举例来说,加入程序要在每天的07:00 和 09:00执行,那么就会是下面这个样子。

0 7,9 * * * command

- 连字符代表时间段,比如程序要在07:10,08:10,09:10执行,如下。

10 7-9 * * * command

/n 代表每隔n单位间隔,比如每隔2分钟执行一次,如下。

*/2 * * * * command


系统配置文件:/etc/crontab,/etc/cron.d/*

这个 crontab -e 是针对每个用户的 cron 来设计的,如果是“系统的例行性任务”时, 只要编辑 /etc/crontab 这个文件就可以,在linux上,系统会每分钟区读取配置文件,所以修改之后无需重启服务即可生效。

特别注意下面的 PATH 坏境变量跟我们的终端shell的坏境变量不一样,比如我的 python3 可执行程序在 /usr/local/bin/python3 在会话终端(PATH 变量包含 /usr/local/bin)时可以成功执行 python3 /root/tmp.py,而在crontab 里只能使用绝对路径 /usr/local/bin/python3 /root/tmp.py。

[root@192 ~]# cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root     #运行发生错误或者是有 stdout/stderr时发送邮件给谁

#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

这里的配置跟上面的 crontab -e里多个 user-name 域,用来指定哪个用户,一般为 root。

一般来说,crond 会默认读取三个地方的配置文件:

/etc/crontab
/etc/cron.d/*
/var/spool/cron/*

[root@192 cron.d]# cat /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

[root@192 cron.d]# ll /etc/cron.hourly/
-rwxr-xr-x. 1 root root 392 Mar 31  2016 0anacron

run-parts 脚本会在大约 5 分钟内随机选一个时间来执行 /etc/cron.hourly 目录内的所有可执行文件。

这里的 0anacron 会执行 /etc/cron.dail/(一天执行一次),/etc/cron.weekly/(一周执行一次),/etc/cron.monthly/(一个月执行一次)。

使用 crontab 时需要注意以下几点:

1.取消不要的输出项目,当有执行成果或者是执行的项目中有输出的数据时,该数据将会 mail 给 MAILTO 设置的帐号 ,那么当有一个调度一直出错就麻烦了,所以可以将stdout/stderr 重定向到 /dev/null。

1 * * * * * root ls -l > /dev/null 2>&1 &

2.安全的校验,因为很多木马都会利用 crontab 方式植入自己的程序,比如前段时间的挖矿病毒,就是利用 admin 用户的漏洞,在 admin 用户的crontab 下写入了自己的要周期重启的程序。用户可以检查 /var/log/cron 或 利用 crontab -u 用户名 -l 来检查是否有非本人设置的 cron。

3.最好验证一次程序是否真的执行了,因为有可能是语法错误,或者是环境变量问题,导致程序一直没有执行。


可唤醒停机间的工作任务

想像一个环境,你的 Linux 服务器有一个工作是需要在每周的星期天凌晨 2 点进行,但是很不巧的,星期六停电了~所以你得要星期一才能进公司去启动服务器。 那么请问,这个星期天的工作调度还要不要进行?因为你开机的时候已经是星期一,所以星期天的工作当然不会被进行,对吧。

anacron 存在的目的就在于我们上头提到的,在处理非 24 小时一直启动的 Linux 系统的 crontab 的执行! 以及因为某些原因导致的超过时间而没有被执行的调度工作。

anacron 程序只保证 /etc/cron.dail/,/etc/cron.weekly/,/etc/cron.monthly/ 下的程序过期能被执行,其他的如写在配置文件 /etc/crontab 里一天执行一次的程序过期了就过期了。

[root@192 cron.d]# cat /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

# 上面的语法在检验前一次执行 anacron 时的时间戳!


# 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

从上面可以看出,0anacron 每一个小时会被 crond 调用一次,从上面可以看出 /etc/cron.dail/,/etc/cron.weekly/,/etc/cron.monthly/ 下的程序都是由 /usr/sbin/anacron调用执行的。

[root@study ~]# anacron [-sfn] [job]..
[root@study ~]# anacron -u [job]..
选项与参数:
-s :开始一连续的执行各项工作 (job) ,会依据时间记录文件的数据判断是否进行;
-f :强制进行,而不去判断时间记录文件的时间戳记;
-n :立刻进行未进行的任务,而不延迟 (delay) 等待时间;
-u :仅更新时间记录文件的时间戳记,不进行任何工作。
job :由 /etc/anacrontab 定义的各项工作名称。

在我们的 CentOS 中,anacron 的进行其实是在每个小时都会被抓出来执行一次, 但是为了 担心 anacron 误判时间参数,因此 /etc/cron.hourly/ 里面的 anacron 才会在文件名之前加个 0 (0anacron) ,让 anacron 最先进行!就是为了让时间戳记先更新!以避免 anacron 误判 crontab 尚未进行任何工作的意思。

/etc/anacrontab

[root@192 cron.d]# 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
天数    延时分钟   名称                   指令
[root@192 cron.d]# cat /var/spool/anacron/cron.daily 
20180705
[root@192 cron.d]# cat /var/spool/anacron/cron.monthly 
20180702
[root@192 cron.d]# cat /var/spool/anacron/cron.weekly 
20180702

我们拿 /etc/cron.daily/ 那一行的设置来说明好了。那四个字段的意义分别是: 

天数:anacron 执行当下时间与 cron.daily 相差的天数,若超过此天数,就准备开始执行,若没有超过此天数,则不予执行后续的指令。

延迟时间:若确定超过天数导致要执行调度工作了,那么请延迟执行的时间,因为担心立即启动会有其他资源冲突的问题吧!

工作名称定义:这个没啥意义,就只是会在 /var/log/cron 里头记载该项任务的名称!通常与后续的目录资源名称相同即可。

实际要进行的指令串:有没有跟 0hourly 很像啊!没错!相同的作法啊!通过 run-parts 来处理的!

根据上面的配置文件内容,我们大概知道 anacron 的执行流程应该是这样的 (以 cron.daily 为例) :
1. 由 /etc/anacrontab 分析到 cron.daily 这项工作名称的天数为 1 天;

2. 由 /var/spool/anacron/cron.daily 取出最近一次执行 anacron 的时间戳记;

3. 由上个步骤与目前的时间比较,若差异天数为 1 天以上 (含 1 天) ,就准备进行指令;

4. 若准备进行指令,根据 /etc/anacrontab 的设置,将延迟 5 分钟 + 3 小时 (看 START_HOURS_RANGE 的设置) ;

5. 延迟时间过后,开始执行后续指令,亦即“ run-parts /etc/cron.daily ”这串指令;

6. 执行完毕后, anacron 程序结束

最后总结下 crond 和 anacron 的关系

1. crond 会主动去读取 /etc/crontab, /var/spool/cron/, /etc/cron.d/ 等配置文件,并依据“分、 时、日、月、周”的时间设置去各项工作调度;

2. 根据 /etc/cron.d/0hourly 的设置,主动去 /etc/cron.hourly/ 目录下,执行所有在该目录下 的可执行文件;

3. 因为 /etc/cron.hourly/0anacron 这个指令档的缘故,主动的每小时执行 anacron ,并调用 /etc/anacrontab 的配置文件;

4. 根据 /etc/anacrontab 的设置,依据每天、每周、每月去分析 /etc/cron.daily/, /etc/cron.weekly/, /etc/cron.monthly/ 内的可执行文件,以进行固定周期需要执行的指令。


备注:
1.本系列命令都在centos7里测试,其他发行版如ubuntu、debian、fedora、opensuse等可能略微不同
2.本文只讲解常用用法,详细用法请自行利用 man 命令查看
3.原文地址http://www.freecls.com/a/2712/87

 

©著作权归作者所有
收藏
推荐阅读
  • linux命令date、time

    date 命令可以显示设置日期和时间。-d 根据指定的字符串来显示时间,必须加上双引号 -s 根据指定的字符串来设置时间 -u 根据utc显示和设置 -R 以 RFC 2822格式输出时间&lt;...

  • linux命令man、locale、selinux

    man 命令可以提供命令或者是c库函数等参考手册,man手册按章节(section)来记录不同类型的页。如果不指定章节,默认按照特定的顺序搜索全部章节,并停留在第一个找到的章节里。下面是对各个章节的解...

  • linux资源限制命令 - ulimit

    ulimit 可以修改当前bash环境的资源限制,这样在当前会话下运行的程序都会继承这些资源限制,默认情况下即设置 软限制,也设置 硬限制,软限制与硬限制的区别读者可以参考linux c进程资源。资源...

  • linux环境变量export、declare、env、readonly、read

    export 可以打印和设置变量。普通变量 只在当前 bash 中有效,新建的子进程都不会继承。环境变量 新创建的子进程会继承。export name #把普通变量name添加到环境变量 export...

  • linux命令history、type

    history 为显示历史记录,读取历史记录到缓冲区和将历史记录从缓冲区独到文件。刚登陆bash的时候会从 ~/.bash_history 中读取 $HISTSIZE 条数据到内存,注销的时候只会记录...

  • nginx模块 ngx_http_headers_module

    ngx_http_headers_module 模块是用来增加 Expires 和 Cache-control,或者是任意的响应头。Syntax: add_header name value [alw...

  • nginx模块 ngx_http_gunzip_module、ngx_http_gzip_module、ngx_http_gzip_static_module

    ngx_http_gunzip_module 模块将文件解压缩后并在响应头加上 "Content-Encoding: gzip" 返回给客户端。为了解决客户端不支持gzip压缩。编译的时候带上 --w...

  • nginx模块 ngx_http_flv_module、ngx_http_mp4_module

    ngx_http_flv_module模块提供了对 flv 视频的伪流支持。编译的时候带上 --with-http_flv_module。它会根据指定的 start 参数来指定跳过多少字节,并在返回数...

  • nginx模块 ngx_http_fastcgi_module

    ngx_http_fastcgi_module 模块使得nginx可以与 fastcgi 服务器通信。比如目前要使得 nginx 支持 php 就得使用 fastcgi技术,在服务器上装上 nginx...

  • nginx模块 ngx_http_autoindex_module

    ngx_http_autoindex_module 模块可以将uri以 / 结尾时,列出里面的文件和目录。Syntax: autoindex on | off; Default: autoindex ...

简介
天降大任于斯人也,必先苦其心志。