生活中或是工作中,经常会有定时执行任务或者重复执行任务的需求,在银河麒麟操作系统中,我们常用at、crontab及anacron这三个工具来实现这些需求。本文主要介绍这些工具的基本使用方法。
操作系统经常会有一些自动执行的任务,例如我们的日志转储、定期校正系统时间、计划性执行某些命令、持续更新locate数据库等,这些任务一般会分为两种类型:一次性任务和循环任务。那要实现这两种类型的任务,麒麟操作系统一般会用到at和cron这个两个命令。
at:一次性执行,执行完就结束了任务。系统默认没有安装at,需要手动安装at安装包,安装成功后,atd守护进程是设置了默认开机自启动的。
crontab:循环定期执行,执行的时间有分钟、小时、周、月、年等设置,定时任务可以使用crontab命令执行,也可以直接将定时任务写在/etc/crontab文件中。cron守护进程默认开机自启动。
01 at一次性执行
当atd守护进程运行在后台时,我们可以使用at命令执行一次性的任务。
安装at命令:
apt install at (在线安装)
dpkg -i at_3.1.18-2kord1_arm64.deb (离线安装)
at命令的执行涉及到用户的权限控制,默认安装情况下,只有一个/etc/at.deny文件,就是禁止某些用户使用at命令执行任务,如果这个文件里面没有写入任何用户名,即为空,就表示所有用户都可以使用at命令。我们可以自己创建一个/etc/at.allow文件,记录允许使用at的用户。这就类似黑名单和白名单的效果,这两个文件的格式都是每行一个用户名。若是两个文件都存在,以/etc/at.allow优先级较高,就是说用户test如果没有写在/etc/at.allow文件中,那不管test有没有写在/etc/at.deny文件中,都没有权限使用at命令。若是两个文件都不存在,那只有root有权限使用at命令。
at命令的语法很简单,在后面加上时间,就可以在指定的时间执行。
at 命令格式:at [选项] 时间
选项:
-m:当at工作完成后,无论命令是否有输出,都用E-mail通知执行at命令的用户;
-c 工作号:显示该at工作的实际内容;
时间:
HH:MM
在指定的“小时:分钟”执行命令,如 11:30;
HH:MM YYYY-MM-DD
在指定的“小时:分钟 年-月-日”执行命令,如 11:30 2019-05-25;
HH:MM[am|pm] [month] [date]
在指定的“小时:分钟[上午|下午][月][日]”执行命令,如 11:30 May 25;
HH:MM[am|pm] + [minutes | hours | days | weeks ]
在指定的时间“再加多久"执行命令,如 now + 5 minutes, 05am+2 hours;
at 命令只要指定正确的时间,就可以输入需要在指定时间执行的命令。这个命令可以是系统命令,也可以是 Shell 脚本。
例1:将test用户分别写入/etc/at.deny和/etc/at.allow文件中,对比权限优先级。
root@kylin-1:# echo test >> /etc/at.deny
root@kylin-1:# su test
test@kylin-1:~$ at 11pm
You do not have permission to use at.
root@kylin-1:# echo test >> /etc/at.allow
root@kylin-1:# su test
test@kylin-1:~$ at 11pm
warning: commands will be executed using /bin/sh
at>
注意上面的例子,/etc/at.deny文件本身是有很多用户的,我们使用两个>符号追加写入,而不是覆盖。使用ctrl+D保存at任务。
例2:设定在未来的某个时间同步数据,然后关机。在进行以下同步数据操作前,本机和远程主机需要提前设置ssh无密码登录。(执行命令ssh-keygen生成本机ssh公钥,执行ssh-copy-id 192.168.100.237拷贝到远程主机上)。
# at 02:00 2024-11-26
at>rsync -r kylin@192.168.100.237:/opt/data /opt/data(假设将远程主机的数据同步到本机)
at> /bin/sync
at> /sbin/shutdown -h now(关机)
at> <EOT>
job 9 at 2024-11-26 02:00
例3:设定在未来的某个时间执行脚本。
# cat /home/kylin/test.sh
echo “this is a test”
#at now + 2 minutes
warning: commands will be executed using /bin/sh
at> /home/kylin/test.sh >> /home/kylin/test.log
at> <EOT>
job 2 at Wed May 22 10:33:00 2024
#cat /home/kylin/test.log
this is a test
上面两个例子,例2是直接执行命令,例3是执行脚本,这里建议大家写绝对路径。
例4:另外还有查询at任务的命令atq,和删除at任务的命令atrm。
# atq
4 Wed May 22 10:43:00 2024 a root
# atrm 4
# atq
#(此时显示为空,任务4已经被删除,没有at任务了)
02 crontab循环定时任务
- cron概述
一些任务(包括定期循环运行的任务)需要在没有人使用计算机资源的时候去运行,如午夜或周末,或者下班后,没有人手动去运行命令或脚本。在上面介绍了一次性定时任务后,如果我们想要每天都在某个时间执行这个任务,可以使用cron服务来设置。cron服务可以安排任务在一个周期上重复,比如天、周、或月。
麒麟操作系统默认安装了cron,cron守护进程也是默认自启动。我们可以通过crontab命令或者修改/etc/crontab文件,来设置循环定时任务。
- crontab配置
cron服务检查/var/spool/cron和/etc/cron.d目录中的文件,以及/etc/anacrontab文件。这些文件的内容定义了以不同的时间间隔运行的cron任务。普通用户的cron 文件位于/var/spool/cron,而系统服务和应用生成的cron作业文件放在/etc/cron.d目录中。
cron程序运行基于一个cron表(crontab)中指定的命令。每个用户,包括 root,都有一个cron文件,这些文件缺省是不存在的。但可以使用crontab -e命令创建在/var/spool/cron目录中,也可以使用该命令去编辑一个cron文件。这里建议,不要使用标准的编辑器(比如,vi、vim、emacs、nano、gedit或者任何其它可用的编辑器),而是使用crontab命令,该命令不仅允许你去编辑cron文件,也可以在你保存并退出编辑器时,重启动cron守护进程。初次使用crontab命令编辑内容,会让我们选择一种编辑器,也可以后面在终端输入select-editor重新选择编辑器。
crontab命令的用法:crontab [-u user] [-l | -e | -r]
参数说明:
-u user:只有root能下达的参数,查看或编译其它用户的crontab内容。
-l:列出crontab的内容。
-e:编辑crontab的内容。
-r:删除crontab的内容,注意-r是删除了所有的命令,如果是修改,用参数-e。
例1:普通用户test要在每天的12:00发信给自己。
test@Kylin-1:~$ crontab -e
# m h dom mon dow user command
0 12 * * * mail test < /home/test/test.txt
注释行,它说明了定义一个cron作业所要求的语法,时间设置,用户名,具体命令。我们从下面的表中可以看到时间设置具体信息。cron支持类似正则表达式的书写,支持如下几个特殊符号定义:
“ * ” 代表所有的取值范围内的数字;
” / “ 代表”每”(“*/5”,表示每5个单位);
” – “ 代表从某个数字到某个数字(“1-4”,表示1-4个单位);
” , “ 代表分开几个离散的数字。
crontab时间说明
数字代表的意义 | 分钟 | 小时 | 日期 | 月 | 周 |
---|---|---|---|---|---|
范围 | 0-59 | 0-23 | 1-31 | 1-12 | 0-7 |
其中周的0-7,0和7都表示星期天。
例2:每间隔5分钟执行一次对时操作,每周五的17:30运行check.sh脚本。
root@Kylin-1:~# crontab -e
# m h dom mon dow user command
*/5 * * * * ntpdate 192.168.100.1
30 17 * * 5 /home/test/chech.sh
对时操作需要root权限,这里我们使用root用户去设置,每周五的check.sh脚本,检查系统的状态等,我们也用root权限去设置。另外,脚本的路径最好是使用绝对路径。
上面介绍的是用户使用crontab命令给各自设置的循环定时任务,现在我们介绍系统的循环定时任务设置,以root用户权限编辑/etc/crontab文件。
root@Kylin-1:~# cat /etc/crontab
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# m h dom mon dow user command
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
我们可以看到前两行设置了一个缺省环境。对于给定用户,环境变量必须是设置的,因为cron不提供任何方式的环境。SHELL变量指定命令运行使用的shell,麒麟系统默认指定为Bash shell。第二行为环境设置了PATH变量。另外,系统默认设置了调用run-parts命令,定时运行四个目录下的所有脚本。
/etc/cron.hourly下的脚本会被每小时运行一次,在每小时的17分时运行。
/etc/cron.daily下的脚本会被每天运行一次,在每天6点25分运行。
/etc/cron.weekly下的脚本会被每周运行一次,在每周第7天的6点47分运行。
/etc/cron.monthly下的脚本会被每月运行一次,在每月1号的6点52分运行。
例3:设置一个目录,让系统可以每2分钟去执行这个目录下的所有可以执行的文件。
root@Kylin-1:~# vim /etc/crontab
*/2 * * * * root run-parts /etc/cron.min
/etc/cron.min这个目录是需要已经存在。那如果我们需要执行的是一个脚本或者程序,而不是一个目录下的所有可执行文件,那我们就和上面的例子一样设置命令就可以了,只需要将run-parts去掉。
我们初次学习定时任务,在crontab文件中设置的时间看上去是随机的。但是当我们以root管理员身份去安排cron作业是件很具有挑战性的事,尤其是作业的数量越来越多时。因为,如果有太多作业在同一时间运行,尤其是备份或者编译系统,会耗尽内存并且几乎填满交换文件空间,这会导致系统性能下降甚至是超负荷,最终什么事情都完不成。所以我们在写crontab的时间安排上要考虑很多,也需要考虑内存优化等。
cron服务是假设主机计算机24小时运行。那意味着如果在一个计划运行的期间关闭计算机,这些计划的任务将不再运行,直到它们计划的下一次运行时间。如果这里有关键的cron作业,这可能导致出现问题。但是我们还有解决方法,就是anacron。
03 anacrontab配置
- anacron概述
anacron程序执行和cron一样的功能,但是它增加了运行被跳过的作业的能力。比如,如果计算机已经关闭或者其它的原因导致无法在一个或多个周期中运行作业。它对笔记本电脑或其它被关闭或进行睡眠模式的电脑来说非常有用。只要电脑一打开并引导成功,anacron 会检查过去是否有计划的作业被错过。如果有,这些作业将立即运行,但是,仅运行一次(而不管它错过了多少次循环运行)。例如,如果一个每周运行的作业在最近三周因为休假而系统关闭都没有运行,它将在你的电脑一启动就立即运行,但是,它仅运行一次,而不是三次。
anacron命令的用法:anacron -[sfn] [jobs]
参数说明:
-s:开始连续执行各项工作(job),根据时间记录文件判断是否进行。
-f:强制执行,不去判断时间记录文件的时间戳。
-n:立刻进行未进行的任务,不延迟等待时间。
-u:仅更新时间记录文件的时间戳,不进行任何工作。
Job:由/etc/anacrontab文件定义的各项工作名称。
- anacrontab配置
anacron的配置文件是/etc/anacrontab,我们打开这个文件可以看到系统会在合适的时间运行在 cron.[daily|weekly|monthly] 目录中的可执行文件。
root@Kylin-1:~#cat /etc/anacrontab
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
HOME=/root
LOGNAME=root
# These replace cron's entries
1 5 cron.daily run-parts --report /etc/cron.daily
7 10 cron.weekly run-parts --report /etc/cron.weekly
@monthly 15 cron.monthly run-parts --report /etc/cron.monthly
前面四行是默认的环境变量。后面三行按照下面的格式来执行作业:
period delay job-identifier command
period是任务的频率,以天来指定,或者是@daily、@weekly、@monthly分别代表每天、每周、每月一次。你也可以使用数字:1表示每天、7表示每周、30表示每月,或者N表示N天。 delay是在执行一个任务前等待的分钟数。 job-id是写在日志文件中任务的独特名字。 command是要执行的命令或 shell脚本。
在系统的/var/spool/anacron/目录中存在cron.{daily,weekly,monthly} 文件,这些文件中都保存着 anacron上次执行的时间。anacron会读取这些文件中的时间,然后和当前时间进行比较,如果两个时间的差值超过anacron的指定时间差值(一般是1天、7天和一个月),就说明有定时任务没有执行,这时anacron会介入而执行这个漏掉的定时任务,从而保证在关机时没有执行的定时任务不会被漏掉。
有两个anacrontab文件的重要变量:
START_HOURS_RANGE:设置任务开始运行的时间范围(也就是任务只在这几个小时期间运行)。
RANDOM_DELAY:定义添加到用户定义的任务延迟的最大随机延迟(默认为 45)。
例4:我们修改默认的配置文件anacrontab文件,让定时任务在凌晨03:00-05:00执行。
root@Kylin-1:~# vim /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分钟,不再强制廷迟
最后,一般来说只有root管理员在计算机上创建了很多计划运行任务,很少有普通用户去需要运行cron任务。限制非root用户去访问cron功能是非常重要的。然而,在一些特殊情况下,用户需要去设置一个任务在预先指定时间运行,而cron可以允许他们去那样做。许多用户不理解如何正确地配置cron去完成任务,那么他们会出错。这些错误可能是无害的,也可能导致问题。通过设置/etc/cron.allow文件,允许某些用户使用cron是很必要的。
我们经常会需要使用crontab进行定时任务,但crontab不能成功执行脚本的情况还是很常见,总结起来,原因主要有以下几个:
- cron守护进程不存在,它必须存在才能让crontab正常使用;
- 系统时间不对;
- 环境变量的问题:crontab执行脚本的时候不会读取用户的环境变量等配置,所以可能很多命令不能使用导致脚本执行失败;
- 脚本本身的问题。
针对以上几点,在使用crontab之前,我们应该:
- 检查crond进程是否正在正常运行;
- 系统时间不对情况很少见,毕竟大多数情况我们的时间都很标准,不过要是用不熟悉的机器,最好还是date一下;
- 环境变量应该是最容易出现的问题了,针对这种问题:
- 在编写shell脚本的时候尽量用绝对路径使用命令;
- 在脚本开头export一下路径(常见的命令一般在/bin,/sbin,/usr/bin,/usr/sbin这几个路径下,所以不妨全部export一下:export PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin,如果不全部export的话,记得把使用到的命令which一下以确定命令的真实路径;
- 使用脚本调用别的脚本,比如有三个脚本:run1.sh,run2.sh,run3.sh,假设这三个脚本都使用了cat、grep等命令,那么它们直接放在crontab中是不会被成功执行的,这时候我们可以写个run.sh,在run.sh中调用run1.sh,run2.sh,run3.sh,这样就不需要考虑export环境变量的问题,因为run.sh并没有使用系统命令,而run.sh调用run1.sh的时候已经不是crontab在管理了,所以会读取用户的环境变量。
- 将脚本先手动执行一次,如果成功执行再考虑crontab相关的问题。
暂无评论内容