Linux 定时任务
at命令:一次性执行定时任务
at 命令要想正确执行,需要 atd 服务的支持。atd 服务是独立的服务,启动的命令如下:
[root@localhost ~]# service atd start
正在启动 atd: [确定]
[root@localhost ~]# chkconfig atd on
atd 服务启动之后,at 命令才可以正常使用,
at 命令的访问控制
这里的访问控制指的是允许哪些用户使用 at 命令设定定时任务,或者不允许哪些用户使用 at 命令。at 命令的访问控制是依靠 /etc/at.allow(白名单)和 /etc/at.deny(黑名单)这两个文件来实现的,具体规则如下:
- 如果系统中有 /etc/at.allow 文件,那么只有写入 /etc/at.allow 文件(白名单)中的用户可以使用 at 命令,其他用户不能使用 at 命令(/etc/at.deny 文件会被忽略,也就是说,同一个用户既写入 /etc/at.allow 文件,又写入 /etc/at.deny 文件,那么这个用户是可以使用 at 命令的,因为 /etc/at.allow 文件的优先级更高)。
- 如果系统中有 /etc/at.allow 文件,那么只有写入 /etc/at.allow 文件(白名单)中的用户可以使用 at 命令,其他用户不能使用 at 命令(/etc/at.deny 文件会被忽略,也就是说,同一个用户既写入 /etc/at.allow 文件,又写入 /etc/at.deny 文件,那么这个用户是可以使用 at 命令的,因为 /etc/at.allow 文件的优先级更高)。
- 如果系统中没有 /etc/at.allow 文件,只有 /etc/at.deny 文件,那么写入 /etc/at.deny 文件(黑名单)中的用户不能使用 at 命令,其他用户可以使用 at 命令。不过这个文件对 root 用户不生效。
- 如果系统中这两个文件都不存在,那么只有 root 用户可以使用 at 命令。
系统中默认只有 /etc/at.deny 文件,而且这个文件是空的,这样系统中所有的用户都可以使用 at 命令。不过,如果我们打算控制用户的 at 命令权限,那么只需把用户写入 /etc/at.deny 文件即可。/etc/at.allow 文件的优先级高,如果 /etc/at.allow 文件存在,则 /etc/at.deny 文件失效。/etc/at.allow 文件的管理更加严格,因为只有写入这个文件的用户才能使用 at 命令,如果需要禁用 at 命令的用户较多,则可以把少数用户写入这个文件。/etc/at.deny 文件的管理较为松散,如果允许使用 at 命令的用户较多,则可以把禁用的用户写入这个文件。不过这两个文件都不能对 root 用户生效。
at命令
at 命令的格式非常简单,只需在 at 命令后面加入时间即可,这样 at 命令就会在指定的时间执行。at 命令格式如下:
[root@localhost ~] # at [选项] 时间
【选项】
- -m:当 at 工作宪成后,无论命令是否有输出,都用 E-mail 通知执行 at 命令的用户;
- -c 工作号: 显示该 at 工作的实际内容;
- HH:MM 在指定的“小时:分钟”执行命令,如 02:30;
- HH:MM YYYY-MM-DD 在指定的“小时:分钟 年-月-日”执行命令,如 02:30 2013-07-25;
- HH:MM[am|pm] [month] [date] 在指定的“小时:分钟[上午|下午][月][日]”执行命令,如 02:30 July 25;
- HH:MM[am|pm] + [minutes | hours | days | weeks ]在指定的时间“再加多久"执行命令,如 now + 5 minutes, 05am +2 hours;
定时执行脚本
[coot@localhost ~]# cat /root/hello.sh #!/bin/bash echo "hello world!!" #该脚本会打印"hello world!!"
使用 at 定时调用
[root@localhost ~]# at now +2 minutes at> /root/hello.sh >> /root/hello.log #执行hello.sh脚本,并把输出写入/root/hello.log文件 at> <EOT> #使用Ctrl+D快捷键保存at任务 job 8 at 2018-12-16 20:54 #这是第8个at任务,会在2018年12月16日20:54执行
查询第8个at任务的内容
[root@localhost ~]# at -c 8 ...省略部分内容... /root/hello.sh >> /root/hello.log #可以看到at执行的任务
在指定的时间关机
在一个at任务中是可以执行多个系统命令的
[root@localhost ~J# at 02:00 2018-12-16 at> /bin/sync at> /sbin/shutdown -h now at> <EOT> job 9 at 2018-12-16 21:00
Ctrl+D
快捷键保存,实际上写入了 /var/spool/at/ 这个目录,这个目录内的文件可以直接被 atd 服务调用和执行。查询当前服务器上的at任务
[root@localhost ~]# atq 9 2018-12-16 21:00 a root #说明root用户有一个at任务在2018-12-16 21:00 执行,工作号是9
删除指定的at任务
[root@localhost ~]# atrm 9 [root@localhost ~]# atq #删除9号at任务,再查询就没有at任务存在了
crontab命令:循环执行定时任务
crond服务管理与访问控制
crontab 命令是需要 crond 服务支持的。crond 服务同样是独立的服务,启动和自启动方法如下:[root@localhost ~]# service crond restart
停止 crond: [确定]
正在启动 crond: [确定]
#重新启动crond服务
设定crond服务为开机自启动
[root@localhost ~]# chkconfig crond on
crond 服务默认是自启动的。如果服务器上有循环执行的系统定时任务,就不要关闭 crond 服务了。
crontab 命令和 at 命令类似,也是通过 /etc/cron.allow 和 /etc/cron.deny 文件来限制某些用户是否可以使用 crontab 命令的。而且原则也非常相似:- 当系统中有 /etc/cron.allow 文件时,只有写入此文件的用户可以使用 crontab 命令,没有写入的用户不能使用 crontab 命令。同样,如果有此文件,/etc/cron.deny 文件会被忽略,因为 /etc/cron.allow 文件的优先级更高。
- 当系统中只有 /etc/cron.deny 文件时,写入此文件的用户不能使用 crontab 命令,没有写入文件的用户可以使用 crontab 命令。
- 这个规则基本和 at 命令的规则一致,同样是 /etc/cron.allow 文件比 /etc/cron.deny 文件的优先级高,Linux 系统中默认只有 /etc/cron.deny 文件。
用户的crontab设置
每个用户都可以实现自己的 crontab 定时任务,只需使用这个用户身份执行“crontab -e”命令即可。当然,这个用户不能写入 /etc/cron.deny 文件。crontab 命令格式如下:[root@localhost ~]# crontab [选项]
- -e:编辑 crontab 定时任务;
- -l:查询 crontab 定时任务;
- -r:删除当前用户所有的 crontab 定时任务。如果有多个定时任务,只想删除一个,则可以使用“crontab -e”;
- -u 用户名:修改或删除其他用户的 crontab 定时任务。只有 root 用户可用;
crontab 文件格式
crontab 编辑的文件中是通过5个“*”来确定命令或任务的执行时间的,这 5 个“*”的具体含义:
项目 | 含义 | 范围 |
---|---|---|
第一个"*" | 一小时当中的第几分钟 | 0~59 |
第二个"*" | 一天当中的第几小时 | 0~23 |
第三个"*" | 一个月当中的第几天 | 1~31 |
第四个"*" | 一年当中的第几个月 | 1~12 |
第五个"*" | 一周当中的星期几 | 0~7(0和7都代表星期日) |
在时间表示中,还有一些特殊符号需要学习:
特殊符号 | 含义 |
---|---|
* | 代表任何时间。比如第一个"*"就代表一小时种每分钟都执行一次的意思 |
, | 代表不连续的时间。比如"0 8,12,16***命令"就代表在每天的8点0分、12点0分、16点0分都执行一次命令 |
- | 代表连续的时间范围。比如"0 5 ** 1-6命令",代表在周一到周六的凌晨5点0分执行命令 |
*/n | 代表每隔多久执行一次。比如"*/10****命令",代表每隔10分钟就执行一次命令 |
当“crontab -e”编辑完成之后,一旦保存退出,那么这个定时任务实际就会写入 /var/spool/cron/ 目录中,每个用户的定时任务用自己的用户名进行区分。而且 crontab 命令只要保存就会生效,只要 crond 服务是启动的。知道了这 5 个时间字段的含义,我们多举几个时间的例子来熟悉一下时间字段,如表 3 所示。
时间 | 含义 |
---|---|
45 22 *** 命令 | 在22点45分执行命令 |
0 17 ** 1 命令 | 在每周一的17点0分执行命令 |
0 5 1,15** 命令 | 在每月1日和15日的凌晨5点0分执行命令 |
40 4 ** 1-5 命令 | 在每周一到周五的凌晨4点40分执行命令 |
*/10 4 *** 命令 | 在每天的凌晨4点,每隔10分钟执行一次命令 |
0 0 1,15 * 1 命令 |
在每月1日和15日的0点0分及每周一的0点0分都会执行命令, 注意:星期几和几日最好不要同时出现,因为定义的都是天,非常容易混淆 |
在“执行的任务”字段中既可以定时执行系统命令,也可以定时执行某个 Shell 脚本。
让系统每隔 5 分钟就向 /tmp/test 文件中写入一行“11”
[root@localhost ~]# crontab -e #进入编辑界面 */5 * * * * /bin/echo "11" >> /tmp/test
如果觉得每隔 5 分钟太长,那就换成“*”,让它每分钟执行一次。而且和 at 命令一样,如果我们定时执行的是系统命令,那么最好使用绝对路径。
让系统在每周二的凌晨5点05分重启一次
[root@localhost ~]# crontab -e 5.5 * * 2 /sbin/shutdown -r now
如果服务器的负载压力比较大,则建议每周重启一次,让系统状态归零。比如绝大多数游戏服务器每周维护一次,维护时最主要的工作就是重启,让系统状态归零。这时可以让我们的服务器自动来定时执行。
在每月1日、10日、15 日的凌晨 3 点 30 分都定时执行日志备份脚本 autobak.sh
[root@localhost ~]# crontab -e 30.3 1,10,15 * * /root/sh/autobak.sh
这些定时任务保存之后,就可以在指定的时间执行了。
查看root用户的crontab任务
[root@localhost ~]# crontab -l */5 * * * * /bin/echo "11" >> /tmp/test 5.5 * * 2 /sbin/shutdown -r now 30.3 1,10,15 * * /root/sh/autobak.sh
删除root用户所有的定时任务
[root@localhost ~]# crontab -r
如果只想删除某个定时任务,则可以执行“crontab -e”命令进入编辑模式手工删除
[root@localhost ~]# crontab -l no crontab for root
删除后,再查询就没有root用户的定时任务了
crontab的注意事项
在书写 crontab 定时任务时,需要注意以下几个事项:- 6 个选项都不能为空,必须填写。如果不确定,则使用“*”代表任意时间。
- crontab 定时任务的最小有效时间是分钟,最大有效时间是月。像 2018 年某时执行、3 点 30 分 30 秒这样的时间都不能被识别。
- 在定义时间时,日期和星期最好不要在一条定时任务中出现,因为它们都以天为单位,非常容易让管理员混淆。
- 在定时任务中,不管是直接写命令,还是在脚本中写命令,最好都使用绝对路径。有时使用相对路径的命令会报错。
系统的crontab设置
“crontab -e”是每个用户都可以执行的命令,也就是说,不同的用户身份可以执行自己的定时任务。但是有些定时任务需要系统执行,这时就需要编辑 /etc/crontab 这个配置文件了。
当然,并不是说写入 /etc/crontab 配置文件中的定时任务在执行时不需要用户身份,而是“crontab -e”命令在定义定时任务时,默认用户身份是当前登录用户。而在修改 /etc/crontab 配置文件时,定时任务的执行者身份是可以手工指定的。
[root@localhost ~]# vi /etc/crontab SHELL=/bin/bash #标识使用哪种Shell PATH=/sbin:/bin:/usr/sbin:/usr/bin #指定PATH环境变量。crontab使用自己的PATH,而不使用系统默认的PATH,所以在定时任务中出现的 #命令最好使用大写 MAILTO=root #如果有报错输出,或命令结果有输出,则会向root发送信息 HOME=/ #标识主目录 # For details see man 4 crontabs #提示大家可以去“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 #分 时日月周执行者身份命令 #列出文件格式,并加入了注释
我们看到 /etc/crontab 中有一句提示,让我们“man 4 crontabs”来查看帮助,在这个帮助中,写明了“在旧版本的 crontab 配置文件中,通过 run-parts 脚本来调用 cron.{daily,weekly,monthly} 目录,定时执行这些目录中的脚本。在当前系统中,为了避免 cron 和 anacron 之间产生冲突,只要 anacron 已经安装,就使用 anacron 来执行这些目录中的脚本。具体可以查看 anacron(8) 的帮助”。 其实,对用户来讲,配置方法都有两种。
第一种方法就是把需要定时执行的工作写成脚本程序,并赋予执行权限,然后直接把这个脚本复制到 /etc/cron.{daily,weekly,monthly} 目录中的任意一个。比如,我需要让某个脚本每周执行,就把这个脚本复制到 /etc/cron.weekly/ 目录中。这样这个脚本就会每周执行一次,具体的执行时间要参考 anacron 的配置文件。
第二种方法就是修改 /etc/crontab 这个配置文件,加入自己的定时任务,不过需要注意指定脚本的执行者身份。例如让系统每分钟都执行一次/root/cron/目录中的脚本,脚本执行者是root用户:
[root@localhost ~]# vi /etc/crontab …省略部分输出… * * * * * root run-parts /root/cron/
虽然在CentOS 6.x中不直接通过此配置文件调用/etc/cron.{daily,weekly,monthly}这些目录,但是run-parts脚本还是可以使用的。所以我完全可以参照CentOS 5.x的方法来写定时任务
使用run-parts脚本调用并执行/root/cron/目录中所有的可执行文件只要保存 /etc/crontab 文件,这个定时任务就可以执行了。当然要确定 crond 服务是运行的。
[root@localhost ~]# mkdir cron #建立/root/cron/目录 [root@localhost cron]# vi /root/cron/hello.sh #/bin/bash echo "hello" >> /root/cron/hello.log #在/root/cron/hello.log文件中写入“hello” [root@localhost cron]# chmod 755 hello.sh #赋予执行权限 #因为hello.sh脚本放入了/root/cron/目录中,所以每分钟执行一次。
这两种方法都是可以使用的,不过,要想修改 /etc/crontab 文件,必须是 root 用户,普通用户不能修改,只能使用用户身份的 crontab 命令。
anacron命令
在系统的 /var/spool/anacron/ 目录中存在 cron.{daily,weekly,monthly} 文件,这些文件中都保存着 anacron 上次执行的时间。anacron 会读取这些文件中的时间,然后和当前时间进行比较,如果两个时间的差值超过 anacron 的指定时间差值(一般是 1 天、7 天和一个月),就说明有定时任务没有执行,这时 anacron 会介入而执行这个漏掉的定时任务,从而保证在关机时没有执行的定时任务不会被漏掉。
在 CentOS 6.x 中使用 cronie-anacron 取代了 vixie-cron 软件包。而且在原先的 CentOS 版本的 /etc/cron.{daily,weekly,monthly} 目录中的定时任务会同时被 cron 和 anacron 调用,这样非常容易出现重复执行同一个定时任务的错误。在 CentOS 6.x 中,/etc/cron.{daily,weekly,monthly} 目录中的定时任务只会被 anacron 调用,从而保证这些定时任务只会在每天、每周或每月定时执行一次,而不会重复执行。
在 CentOS 6.x 中 anacron 还有一个变化,那就是 anacron 不再是单独的服务,而变成了系统命令。也就是说,我们不再使用“service anacron restart”命令来管理 anacron 服务了,而需要使用 anacron 命令来管理 anacron 工作。anacron命令格式如下:
[root@localhost ~]# anacron [选项] [参数]
[选项]:
- -s:开始执行 anacron 工作,依据 /etc/anacrontab 文件中设定的延迟时间执行;
- -s:开始执行 anacron 工作,依据 /etc/anacrontab 文件中设定的延迟时间执行;
- -n:立即执行 /etc/anacrontab 中所有的工作,忽略所有的延迟时间;
- -u:更新 /var/spool/anacron/cron.{daily,weekly,monthly} 文件中的时间戳,但不执行任何工作;
[参数]:
- 工作名:依据 /etc/anacrontab 文件中定义的工作名;
在当前的 Linux 中,其实不需要执行任何 anacron 命令,只需要配置好 /etc/anacrontab 文件,系统就会依赖这个文件中的设定来通过 anacron 执行定时任务了。这个文件的内容如下:
[root@localhost ~]# vi /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 #前面的内容和/etc/crontab类似 #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_H0URS_RANGE=3-22 fanacron的执行时间范围是3:00~22:00 #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 #天数 强制延迟(分) 工作名称 实际执行的命令 #当时间差超过天数时,强制延迟多少分钟之后就执行命令
在这个文件中,“RANDOM_DELAY”定义的是最大随机延迟,也就是说,cron.daily 工作如果超过 1 天没有执行,则并不会马上执行,而是先延迟强制延迟时间,再延迟随机延迟时间,之后再执行命令;“START_HOURS_RANGE”的是定义 anacron 执行时间范围,anacron 只会在这个时间范围内执行。
我们用 cron.daily 工作来说明一下 /etc/anacrontab 的执行过程:
- 读取 /var/spool/anacron/cron.daily 文件中 anacron 上一次执行的时间。
- 和当前时间比较,如果两个时间的差值超过1天,就执行cron.daily工作。
- 只能在 03:00-22:00 执行这个工作。
- 执行工作时强制延迟时间为 5 分钟,再随机延迟 0~45 分钟。
- 使用 nice 命令指定默认优先级,使用 run-parts 脚本执行 /etc/cron.daily 目录中所有的可执行文件。
大家会发现,/etc/cron.{daily,weekly,monthly} 目录中的脚本在当前的 Linux 中是被 anacron 调用的,不再依靠 cron 服务。不过,anacron 不用设置多余的配置,我们只需要把需要定时执行的脚本放入 /etc/cron.{daily,weekly,monthly} 目录中,就会每天、每周或每月执行,而且也不再需要启动 anacron 服务了。如果需要进行修改,则只需修改 /etc/anacrontab 配置文件即可。
比如,让定时任务在凌晨 03:00-05:00 执行,就可以进行如下修改:
[root@localhost ~] # vi /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=0 #把最大随机廷迟改为0分钟,不再随机廷迟 # the jobs will be started during the following hours only START_HOORS_RANGE=3-5 #执行时间范围为03:00—05:00 #period in days delay in minutes job-identifier command 1 0 cron.daily nice run-parts /etc/cron.daily 7 0 cron.weekly nice run-parts /etc/cron.weekly @monthly 0 cron.monthly nice run-parts /etc/cron.monthly #把强制延迟也改为0分钟,不再强制廷迟
这样,所有放入 /etc/cron.{daily,weekly,monthly} 目录中的脚本都会在指定时间执行,而且也不怕服务器万一关机的情况了。