shell脚本控制——定时运行作业

server/2025/2/11 13:54:23/

在使用脚本时,你也许希望脚本能在以后某个你无法亲临现场的时候运行。Linux系统提供了多个在预选时间运行脚本的方法:at命令、cron表以及anacron。每种方法都使用不同的技术来安排脚本的运行时间和频率。接下来将依次介绍这些方法。

1.使用at命令调度作业

at命令允许指定Linux系统何时运行脚本。该命令会将作业提交到队列中,指定shell何时运行该作业。

at的守护进程atd在后台运行,在作业队列中检查待运行的作业。很多Linux发行版会在启动时运行此守护进程,但有些发行版甚至都没安装这个软件包。如果你的Linux属于后一种情况,则可以自行安装,软件包的名字如你所料,就是at。

atd守护进程会检查系统的一个特殊目录(通常位于/var/spool/at或/var/spool/cron/atjobs),从中获取at命令提交的作业。在默认情况下,atd守护进程每隔60秒检查一次这个目录。如果其中有作业,那么atd守护进程就会查看此作业的运行时间。如果时间跟当前时间一致,就运行此作业。

接下来将介绍如何用at命令提交作业以及如何管理作业。

1.at命令的格式

at命令的基本格式非常简单:

at  [-f  filenametime

在默认情况下,at命令会将STDIN的输入放入队列。你可以用-f选项指定用于从中读取命令(脚本文件)的文件名。

time选项指定了你希望何时运行该作业。如果指定的时间已经过去,那么at命令会在第二天的同一时刻运行指定的作业。

指定时间的方式非常灵活。at命令能识别多种时间格式。

  • 标准的小时和分钟,比如10:15
  • AM/PM指示符,比如10:15 PM。
  • 特定的时间名称,比如now、noon、midnight或者teatime(4:00 p.m.)。

除了指定运行作业的时间,也可以通过不同的日期格式指定特定的日期。

  • 标准日期,比如MMDDYY、MM/DD/YY或DD.MM.YY。
  • 文本日期,比如Jul 4或Dec 25,加不加年份均可。
  • 时间增量。
    • Now + 25 minutes
    • 10:15 PM tomorrow
    • 10:15 + 7 days

提示        at命令可用的日期和时间格式有很多种,具体参见/usr/share/doc/at/timespec文件。

在使用at命令时,该作业会被提交至作业队列。作业队列保存着通过at命令提交的待处理作业。针对不同优先级,有52种作业队列。作业队列通常用小写字母a~z和大写字母A~Z来指代,A队列和a队列是两个不同的队列。

注意        在几年前,batch命令也能指定脚本的执行时间。这是个很独特的命令,因为它可以安排脚本在系统处于低负载时运行。现在,batch命令只不过是一个脚本而已(/usr/bin/batch) ,它会调用at命令将作业提交到b队列中。

作业队列的字母排序越高,此队列中的作业运行优先级就越低(谦让度更大) 。在默认情况下,at命令提交的作业会被放入a队列。如果想以较低的优先级运行作业,可以用-q选项指定其他的队列。如果相较于其他进程你希望你的作业尽可能少地占用CPU,可以将其放入z队列。

2.获取作业的输出

当在Linux系统中运行at命令时,显示器并不会关联到该作业。Linux系统反而会将提交该作业的用户email地址作为STDOUT和STDERR。任何送往STDOUT或STDERR的输出都会通过邮件系统传给该用户。

来看一个在CentOS发行版中使用at命令调度作业的例子:

bash">$ cat tryat.sh
#!/bin/bash
# Trying out the at command
#
echo "This script ran at $(date +%B%d,%T)"
echo
echo "This script is using the $SHELL shell."
echo
sleep 5
echo "This is the script's end."
#
exit
$
$ at -f tryat.sh now
warning: commands will be executed using /bin/sh
job 3 at Fri Feb 7 16:23:00 2025
$

at命令会显示分配给作业的作业号以及为作业安排的运行时间。-f选项指明使用哪个脚本文件。now指示at命令立刻执行该脚本。

注意        无须在意at命令输出的警告消息,因为脚本的第一行是#!/bin/bash,该命令会由bash shell执行。

使用email作为at命令的输出极不方便。at命令通过sendmail应用程序发送email。如果系统中没有安装sendmail,那就无法获得任何输出。因此在使用at命令时,最好在脚本中对STDOUT和STDERR进行重定向,如下例所示:

bash">$ cat tryatout.sh
#!/bin/bash
# Trying out the at command redirecting output
#
outfile=$HOME/scripts/tryat.out
#
echo "This script ran at $(date + %B%d,%T)" > $outfile
echo >> $outfile
echo "This script is using the $SHELL shell." >> $outfile
echo >> $outfile
sleep 5
echo "This is the script's end." >> $outfile
#
exit
$
$ at -M -f tryatout.sh now
warning: commands will be executed using /bin/sh
job 4 at Fri Feb 7 16:48:00 2025
$
$ cat $HOME/scripts/tryat.out
This scrit ran at Feb7,16:48:21This script is using the /bin/bash shell.This is the script's end.
$

 如果不想在at命令中使用email或者重定向,则最好加上-M选项,以禁止作业产生的输出信息。

3.列出等待的作业

atq命令可以查看系统中有哪些作业在等待:

bash">$ at -M -f tryatout.sh teatime
warnign: commands will be executed using /bin/sh
job 5 at Sat Feb 8 16:00:00 2025
$
$ at -M -f tryatout.sh tomorrow
warning: commands will be executed using /bin/sh
jb 6 at Sat Feb 8 16:53:00 2025
$
$ at -M -f tryatout.sh 20:30
warning: commands will be executed using /bin/sh
job 7 at Fri Feb 7 20:30:00 2025
$
$ at -M -f tryatout.sh now+1hour
warning: commands will be executed using /bin/sh
job 8 at Fri Feb 7 17:54:00 2025
$
$ atq
1      Fri Feb 7 16:11:00 2025 a christine
5      Sat Feb 8 16:00:00 2025 a christine
6      Sat Feb 8 16:53:00 2025 a christine
7      Fri Feb 7 20:30:00 2025 a christine
8      Fri Feb 7 17:54:00 2025 a christine
$

作业列表中显示了作业号、系统运行该作业的日期和时间,以及该作业所在的作业队列。

4.删除作业

一旦知道了哪些作业正在作业队列中等待,就可以用atrm命令删除等待中的作业。指定要删除的作业号即可:

bash">$ atq
1      Fri Feb 7 16:11:00 2025 a christine
5      Sat Feb 8 16:00:00 2025 a christine
6      Sat Feb 8 16:53:00 2025 a christine
7      Fri Feb 7 20:30:00 2025 a christine
8      Fri Feb 7 17:54:00 2025 a christine
$
$ atrm 5
$
$ atq
1      Fri Feb 7 16:11:00 2025 a christine
6      Sat Feb 8 16:53:00 2025 a christine
7      Fri Feb 7 20:30:00 2025 a christine
8      Fri Feb 7 17:54:00 2025 a christine
$

只能删除自己提交的作业,不能删除其他人的。

2.调度需要定期运行的脚本

使用at命令安排在未来的预设时间运行某个脚本固然不错,但如果需要脚本在每天、每周或每月的同一时间运行呢?这时候与其频繁使用at命令,不如利用Linux系统的另一个特性。

Linux系统使用cron程序调度需要定期执行的作业。cron在后台运行,并会检查一个特殊的表(cron时间表),从中获知已安排执行的作业。

1.cron时间表

cron时间表通过一种特别饿格式指定作业何时运行,其格式如下:

minutepasthour hourofday dayofmonth month dayofweek command

cron时间表允许使用特定值、取值范围(比如1~5)或者通配符(星号)来指定各个字段。如果想在每天的10:15运行一个命令,可以使用如下cron时间表字段:

15  10  *  *  *  command

dayofmonth、month以及dayofweek字段中的通配符表明,cron会在每天10:15执行该命令。要指定一条在每周一的下午4:15(4:15 p.m.)执行的命令,可以使用军事时间(1:00 p.m.是13:00,2:00 p.m.是14:00,3:00 p.m.是15:00,以此类推),如下所示:

15  16  *  *  1  command

可以使用三字符的文本值(mon、tue、web、thu、fri、sat、sun)或数值(0或7代表周日,6代表周六)来指定dayofweek字段。

这里还有另一个例子。要想在每月第一天的中午12点执行命令,可以使用下列字段:

00  12  1  *  *  command

dayofmonth字段指定的是月份中的日期值(1~31)。

提示        聪明的你可能会思考,如何设置才能让命令在每月的最后一天执行,因为无法设置一个dayofmonth值,涵盖所有月份的最后一天。常用的解决方法是加一个if-then语句,在其中使用date命令检查明天的日期是不是某个月份的第一天(01):

00 12 28-31 * * if [ "$(date +%d -d tomorrow)" = 01 ] ; then command ; fi

这行脚本会在每天中午12点检查当天是不是当月的最后一天(28~31),如果是,就由cron执行command

另一种方法是将command替换成一个控制脚本(controlling script),在可能是每月最后一天的时候运行。控制脚本包含if-then语句,用于检查第二天是否为某个月的第一天。如果是,则由控制脚本发出命令,执行必须在当月最后一天执行的内容。

命令列表必须指定要运行的命令或脚本的完整路径。你可以像在命令行中那样,添加所需的任何选项和重定向符:

15  10  *  *  *  /home/christine/backup.sh > backup.out

cron程序会以提交作业的用户身份运行该脚本,因此你必须有访问该脚本(或命令) 以及输出文件的合理权限。

2.构建cron时间表

每个用户(包括root用户)都可以使用自己的cron时间表运行已安排好的任务。Linux提供了crontab命令来处理cron时间表。要列出已有的cron时间表,可以用-l选项:

bash">$ crontab -l
no crontab for christine
$

在默认情况下,用户的cron时间表文件并不存在。可以使用-e选项向cron时间表添加字段。在添加字段时,crontab命令会启动一个文本编辑器,使用已有的cron时间表作为文件内容(如果时间表不存在,就是一个空文件)。

3.浏览cron目录

如果创建的脚本对于执行时间的精确性要求不高,则用预配置的cron脚本目录会更方便。预配置的基础目录共有4个:hourly、daily、monthly和weekly。

bash">$ ls /etc/cron.*ly
/etc/cron.daily:
0anacron  apt-compat    cracklib-runtime  logrotate  [...]
apport    bsdmainutils  dpkg              man-db     [...]/etc/cron.hourly:/etc/cron.monthly:
0anacron/etc/cron.weekly:
0anacron  man-db  update-notifier-common
$

如果你的脚本需要每天运行一次,那么将脚本复制到daily目录,cron就会每天运行它。

4.anacron程序

cron程序唯一的问题是它假定Linux系统是7 x 24小时运行的。除非你的Linux运行在服务器环境,否则这种假设未必成立。

如果某个作业在cron时间表中设置的运行时间已到,但这时候Linux系统处于关闭状态,那么该作业就不会运行。当再次启动系统时,cron程序不会再去运行那些错过的作业。为了解决这个问题,许多Linux发行版提供了anacron程序。

如果anacron判断出某个作业错过了设置的运行时间,它会尽快运行该作业。这意味着如果Linux系统关闭了几天,等到再次启动时,原计划在关机期间运行的作业会自动运行。有了anacron,就能确保作业一定能运行,这正是通常使用anacron代替cron调度作业的原因。

anacron程序只处理位于cron目录的程序,比如/etc/cron.monthly。它通过时间戳来判断作业是否在正确的计划间隔内运行了。每个cron目录都有一个时间戳文件,该文件位于/var/spool/anacron:

bash">$ ls /var/spool/anacron
cron.daily cron.monthly cron.daily
$
$ sudo cat /var/spool/anacron/cron.daily
[sudo] password for christine:
20250208
$

anacron程序使用自己的时间表(通常位于/etc/anacrontab)来检查作业目录:

bash">$ cat /etc/anacrontab
# /etc/anacrontab: configuration file for anacron# See anacron(8) and anacrontab(5) for details.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
$

anacron时间表的基本格式和cron时间表略有不同:

period  delay  identifier  command

period字段定义了作业的运行频率(以天为单位)。anacron程序用该字段检查作业的时间戳文件。delay字段指定了在系统启动后,anacron程序需要等待多少分钟再开始运行错过的脚本。

注意        anacron不会运行位于/etc/cron.hourly目录的脚本。这是因为anacron并不处理执行时间需求少于一天的脚本。

identifier字段是一个独特的非空字符串,比如cron.weekly。它唯一的作用是标识出现在日志消息和错误email中的作业。command字段包含了run-parts程序和一个cron脚本目录名。run-parts程序负责运行指定目录中的所有脚本。

at、cron和anacron在调度作业运行方面各占有一席之地。然而,你可能希望在用户启动新的bash shell而不是特定时刻执行某个脚本。


http://www.ppmy.cn/server/166763.html

相关文章

4.3 线性回归的改进-岭回归/4.4分类算法-逻辑回归与二分类/ 4.5 模型保存和加载

4.3.1 带有L2正则化的线性回归-岭回归 岭回归,其实也是一种线性回归,只不过在算法建立回归方程的时候1,加上正则化的限制,从而达到解决过拟合的效果 4.3.1.1 API 4.3.1.2 观察正则化程度的变化,对结果的影响 正则化力…

孤立森林排除“异常值”可以提高模型效能?

孤立森林排除“异常值”可以提高模型效能的论证 排除异常值可以让数据集的分布相对更加集中,更有利于算法的拟合,所以,设想是适当地去掉异常值,可以提高模型的效能。 为了证明以上的设想,使用两个数据集来分别在排除…

唯一值校验的实现思路(续)

本文接着上一篇文章《唯一值校验的实现思路》,在后端实现唯一值校验。用代码实现。 /*** checkUniqueException[唯一值校验]** param entity 新增或编辑的学生实体* param insert 是否新增,如果是传入true;反之传入false* return void* date…

Python3命令行交互不能使用方向键

个人博客地址:Python3命令行交互不能使用方向键 | 一张假钞的真实世界 自定义安装Python3后在命令行使用方向键时出现以下问题: $ python3 Python 3.7.4 (default, Dec 11 2019, 17:40:08) [GCC 7.4.0] on linux Type "help", "copyri…

PyCharm结合DeepSeek-R1

PyCharm结合DeepSeek-R1,打造专属 AI 编程助手 在程序员的日常工作中,提高编程效率、快速解决代码问题是重中之重。今天给大家分享一个强强联合的组合 ——PyCharm 插件 Continue 与 DeepSeek-R1,它们能帮你打造出强大的个人 AI 编程助手。 …

基于单片机的高精度智能电子秤设计

标题:基于单片机的高精度智能电子秤设计 内容:1.摘要 摘要:本文介绍了一种基于单片机的高精度智能电子秤设计。该电子秤采用了高精度传感器和先进的信号处理技术,能够实现快速、准确的称重。设计中还融入了智能化功能,如数据存储、单位换算、…

RsAbC CTF解密工具

在 CTF(Capture The Flag)竞赛中,加密题是不可或缺的一部分,而 RSA 加密作为最常见的加密算法之一,常常出现在各类题目中。和大家分享一款我在 CTF 备赛过程中发现工具RsAbC,它能帮助我们解决基本RSA 加密相…

Ubuntu禁止内核自动更新

在Ubuntu中,内核的自动更新有时会导致系统不稳定,特别是在运行关键任务的服务器上。因此,禁用内核的自动更新是一个重要的操作。下面是详细的步骤,帮助您在Ubuntu系统中禁用内核自动更新。 一、锁定内核版本 通过锁定内核版本&a…