文章目录
什么是计划任务
计划任务是一种用于在特定时间或条件下自动执行特定任务或程序的技术。在计算机中,计划任务通常指的是操作系统提供的一种机制,允许用户安排在未来的特定时间点或按照特定的时间间隔执行特定操作。这些操作可以是运行脚本、执行命令、启动程序等。
Linux计划任务的种类:at、crontab
有两种计划任务模式:
一种是例行性的:就是每隔一定的周期要来办的事项
一种是突发性的:就是这次做完以后就没有的那一种
Linux实现这两种计划任务模式有两个命令【at】和【crontab】
at
:at是个可以处理仅执行一次就结束的命令,不过要执行at时,必须要有atd这个服务的支持才行。crontab
:crontab这个命令所设置的任务将会循环地一直执行下去,可循环的时间为分钟、小时、每周、每月或每年等。crontab除了可以使用命令执行外,还可以编辑/etc/crontab来支持,执行crontab需要crond这个服务支持才行。
Linux系统上常见的例行性工作
- 系统日志管理: 定期清理系统日志文件,以释放磁盘空间并确保系统正常运行。可以设置计划任务来定期执行日志文件的轮转和删除操作
- 数据备份: 定期备份重要数据以防止意外数据丢失。可以设置定时任务来执行数据备份任务,例如使用 rsync 或 tar 命令等
- 定时重启: 定期重启系统或重启特定服务,以提高系统稳定性和性能。
- 清理临时文件: 定期清理系统中的临时文件和缓存,以释放磁盘空间。
仅执行一次的计划任务:at
atd的启动与at运行的方式
atd的启动
使用仅执行一次的计划任务时,Linux系统上面必须要有负责这类计划任务的服务,那就是atd服务。
atd服务Linux发行版都是默认启动的,某些时刻需要自己手动启动一下才行
# 查看一下atd目前的状态
[root@chenshiren ~]# systemctl status atd
● atd.service - Deferred execution scheduler
Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; preset: enabled)
# enabled 就是是否开机启动,开机启动
Active: active (running) since Fri 2024-03-22 11:43:31 CST; 7h ago
# 是否再运行,running在运行
Docs: man:atd(8)
Main PID: 1174 (atd)
Tasks: 1 (limit: 50264)
Memory: 308.0K
CPU: 1ms
CGroup: /system.slice/atd.service
└─1174 /usr/sbin/atd -f
3月 22 11:43:31 chenshiren systemd[1]: Started Deferred execution scheduler.
# 如果没有在运行可以执行如下
# 开启atd这个服务
[root@chenshiren ~]# systemctl start atd
# 重启atd这个服务
[root@chenshiren ~]# systemctl restart atd
# 设置atd这个服务开机自启
[root@chenshiren ~]# systemctl enable atd
at的运行的方式
at命令用于创建计划任务,将任务排入计划表中等待执行。要执行任务,通常会使用at命令,并将任务以文本文件的形式写入/var/spool/at
目录,然后由atd
服务来执行。然而,并非所有用户都可以执行at计划任务。基于安全考虑,许多主机可能不允许所有用户使用at命令,因为恶意软件可能利用计划任务执行恶意操作或收集系统信息,并将其发送给黑客团体。 为了对at命令进行管控,可以利用/etc/at.allow
和/etc/at.deny
这两个文件。这两个文件的作用如下:
- 首先查找
/etc/at.allow
文件,只有在该文件中列出的用户才能使用at命令,未在其中列出的用户将无法使用at(即使未列在/etc/at.deny
中)。 - 如果
/etc/at.allow
文件不存在,则会查找/etc/at.deny
文件。在/etc/at.deny
中列出的用户将无法使用at命令,而未列出在该文件中的用户则可以使用at。
在大多数Linux发行版中,默认假设系统上的所有用户都是可信任的,因此系统通常会保留一个空的/etc/at.deny
文件,允许所有用户使用at
命令。但如果不希望某些用户使用at
命令,只需在/etc/at.deny
中将其账户名单独列出即可,每个账户名占一行。
实际运行单一计划任务
[root@chenshiren ~]# at [-mldv] TIME
[root@chenshiren ~]# at -c 任务号码
TIME : 时间格式,这里可以定义出【什么时候要执行at这项任务】的时间,格式有
HH:MM :在今日的HH:MM执行,若该时刻已超过,则明天的HH:MM执行此任务
HH:MM YYYY-MM-DD :强制规定在某年某月的某一天的特殊时刻执行该任务
HH:MM[am|pm] [Month] [Date]:强制在某年某月某日某时刻执行
HH:MM[am|pm] + number [minutes|hours|days|weeks]:在某个时间段【再加几个时间后】才执行
选项 | 作用 |
---|---|
-m | 当at任务完成后,即使没有输出信息,也发email通知使用者该任务已完成 |
-l | at -l 相当于atq,列出目前系统上面的所有该使用者的at计划 |
-d | at -d相当于atrm,可以取消一个at计划中的任务 |
-v | 可以使用较明显的时间格式列出at计划中的任务列表 |
-c | 可以列出后面接的该项任务的实际命令内容 |
# 示例1 再过5分钟后,将/root/.bashrc发给root自己
[root@chenshiren ~]# at now + 5 minutes
warning: commands will be executed using /bin/sh
at> /bin/mail -s "testing at job" root < /root/.bashrc
at> <EOT> # 输入ctrl+D 会出现<EOT>
job 9 at Fri Mar 22 20:23:00 2024
# 上面这行消息说明,第9个at任务在2024/3/22 20:23 执行
# 示例2 将上述任务内容列出来查看
[root@chenshiren ~]# at -c 9
#!/bin/sh
# atrun uid=0 gid=0
# mail root 0
umask 22
....
....
....
cd /root || {
echo 'Execution directory inaccessible' >&2
exit 1
}
${SHELL:-/bin/sh} << 'marcinDELIMITER71c90531'
/bin/mail -s "testing at job" root < /root/.bashrc
marcinDELIMITER71c90531
# 可以看到命令执行的目录(/root),还有多个环境变量与实际的命令内容
# 示例3 由于今天晚上11:30停电,我想要在今天晚上11:00关机
[root@chenshiren ~]# at 23:30 2024-3-22
warning: commands will be executed using /bin/sh
at> /bin/sync
at> /bin/sync
at> /sbin/shutdown -h now
at> <EOT>
job 3 at Fri Mar 22 23:30:00 2024
# 示例4 删除示例4的计划任务
[root@chenshiren ~]# at -d 3
[root@chenshiren ~]# at -c 3
Cannot find jobid 3
# 示例5 在1分钟后在终端显示hello,world
[root@chenshiren ~]# at now+1min
warning: commands will be executed using /bin/sh
at> echo "hello,world!" > /dev/pts/0
at> <EOT>
job 12 at Fri Mar 22 20:30:00 2024
# 为什么不是echo "hello,world" 为什么加 > 重定向到/dev/pts/0
# 因为at的执行与终端无关,所有的标准输出/标准错误输出都会发送到执行者的mailbox中
# 所以在终端看不到任何消息,可以通过终端的设备来处理
# 使用w命令来查看你在那个设备登陆,则可以使用【echo "hello" > /dev/你登陆的终端】
# 建议最好使用绝对路径来执行命令,避免出现问题。
循环执行的计划任务:crontab
用户的配置
用户想要建立循环计划任务时,使用的是crontab这个命令
为了避免安全性的问题与at同样,可以限制使用crontab的用户账号
/etc/cron.allow
未在其中列出的用户将无法使用crontab,一个账号一行
/etc/cron.deny
在列出的用户将无法使用at命令,一个账号一行
与 at很像。同样的,以优先级来说,/etc/cron.alow 比比/etc/cron.deny 要优先
在Linux系统中,用户使用crontab
命令建立计划任务后,这些任务会被记录在/var/spool/cron/用户名
文件中。为了避免语法错误导致任务无法执行,不建议直接编辑该文件。每个用户的计划任务都以其用户名作为区分。
此外,系统会将每项cron任务执行的记录写入/var/log/cron
日志文件中。如果怀疑系统可能被植入木马,可以查看该日志文件以获取任务执行记录。
[root@chenshiren ~]# crontab [-u username] [-|-e|-r]
选项:
-u :只有root才能执行这个任务,也就是帮其他使用者建立/删除crontab计划任务
-e :编辑crontab的任务内容
-l : 查看crontab的计划内容
-r : 删除所有的crontab的任务内容,若仅删除一项,用-e去编辑
# 示例1 用csq的身份在每天的12:00发信给自己
[root@chenshiren ~]# crontab -e
0 12 * * * mail -s "at 12:00" csq < /home/csq/.bashrc
# 分 时 日 月 周 ====命令串====
六个字段的意义
意义 | 分钟 | 小时 | 日期 | 月份 | 周 | 命令 |
---|---|---|---|---|---|---|
数字范围 | 0~59 | 0~23 | 1~31 | 1~12 | 0~7 | 需要执行的命令 |
特殊字符的意义
特殊字符 | 意义 |
---|---|
*(星号) | 代表任何时刻都接受的意思。 例如上述示例1 日月周都是*,代表【不论何月、何日的星期几的12:00都指向后续的命令】的意思 |
,(逗号) | 代表分隔时段的意思 例如:如果要执行的任务是3:00与6:00时,就会是0 3,6 * * * command |
-(减号) | 代表一段时间范围内 例如:8点到12点之间的每小时20分都执行一项任务,就会是 20 8-12 * * * command |
/n(斜线) | 那个n代表数字,也就是【每隔n单位间隔】的意思,例如每5分钟执行一次 也就是 */5 * * * * command |
# 示例1 在3月22日 21:34发送一封信给csq这个用户,信内容写在/root/givecsq.txt内
34 21 22 3 * mail csq < /root/givecsq.txt
# 示例2 每5分钟执行/home/csq/test.sh一次
*/5 * * * * /home/csq/test.sh
# 示例3 查看用户目前的crontab内容
[root@chenshiren ~]# crontab -l
0 12 * * * mail -s "at 12:00" csq < /home/csq/.bashrc
34 21 22 3 * mail csq < /root/givecsq.txt
# 示例4 删除全部crontab任务
[root@chenshiren ~]# crontab -r
[root@chenshiren ~]# crontab -l
no crontab for root
系统的配置文件:/etc/crontab、/etc/cron.d/*
在Linux系统中,crontab -e
命令用于管理用户的cron任务,而针对系统的例行性任务,可以编辑/etc/crontab
文件来实现。需要注意的是,/etc/crontab
是一个纯文本文件,可以用root权限编辑。
Cron服务的最小时间单位是分钟,因此cron每分钟会读取一次/etc/crontab
和/var/spool/cron
中的任务内容。编辑完/etc/crontab
文件并保存后,cron会自动执行其中设置的任务。
[root@chenshiren ~]# cat /etc/crontab
SHELL=/bin/bash # 使用哪种shell
PATH=/sbin:/bin:/usr/sbin:/usr/bin # 执行文件查找路径
MAILTO=root # 指示了系统在执行crontab中的任务时,将任务的输出结果发送到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
# 分 时 日 月 周 身份 命令
# 与crontab -e 不同的是需要指定用户身份,系统默认是以root的身份来执行的
crond服务读取配置文件的位置
一般来说,crond默认有3个地方会执行脚本配置文件,分别是:
- /etc/crontab
- /etc/cron.d/*
- /var/spool/cron/*
跟系统的运行有关系的两个配置文件是/etc/crontab文件以及/etc/cron.d/*目录内的文件
另一个是跟用户自己的任务有关系的配置文件,放在/var/spool/cron/ 里面的文件
[root@chenshiren ~]# ls -l /etc/cron.d
总用量 4
-rw-r--r--. 1 root root 128 7月 11 2022 0hourly
[root@chenshiren ~]# 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
如果想要开发自己的软件,该软件要拥有自己的crontab定时命令时,就可以将【分、时、日、月、周、身份、命令】的设置文件放置到/etc/cron.d/目录下。在此目录下的文件是【crontab的配置文件脚本】
run-parts 脚本会在大约5 分钟内随机选一个时间来执行 /etc/cron.hourly 目录内的所有执行文件
。因此放在 /etc/cron.houry/ 的文件,必须是能被直接执行的命令脚本,而不是分、时、日、月、周的设置值,注意注意。
你也可以直接将命令放置到(或链接到)/etc/cron.hourly/ 目录下,这样该命令就会被 crond 在每小时的第1分钟开始后的5分钟内,随机取一个时间点来执行,你无须手动去指定分、时、日、月、周。
除了可以直接将命令放到 /etc/cron.hourly/,让系统每小时定时执行之外,在/etc/下面其实还有/etc/cron.daily/、/etc/cron.weekly/、/etc/cron.monthly/,这三个目录是代表每日、每周、每月各执行一次
- 个人操作使用【crontab -e】:如果你是根据个人需求来建立例行计划任务,建议直接使用【crontab -e】
- 系统维护管理使用【vim /etc/crontab】:如果你这个例行计划任务是系统的重要任务,为了让自己管理方便,同时容易追踪,建议直接写入 /etc/crontab 较佳
- 自己开发软件使用【vim /etc/cron.d/newfile】:如果是自己开发软件,放置于/etc/cron.d/目录即可
可唤醒停机期间的工作任务
如果你的 Linux 服务器有一个任务是需要在每周的星期天凌晨2点执行,但是很不巧星期六停电了,所以你得要星期一才能进公司去启动服务器。那么请问,这个星期天的计划任务还要不要执行?因为你开机的时候已经是星期一,所以星期天的任务当然不会被执行
这时候就要靠 anacron 这个命令的功能了。这不命令可以主动帮你执行时间到了但却没有执行的计划任务
什么是anacron
简而言之,anacron
并不是用来替代crontab
的,它的存在是为了处理那些在非24小时运行的Linux系统中由于系统关闭或其他原因导致未被执行的任务。anacron
每小时由crond
执行一次,检测系统中是否有超时未执行的任务,如果有,则会执行这些任务。它默认以一天、七天和一个月为时间周期来检测未执行的crontab
任务,适用于一些特殊环境下,比如周末或假期系统关闭的情况。 anacron
通过读取时间记录文件(timestamps)来了解系统的关机记录,比较当前时间和上次运行anacron
的时间差异,以此判断是否有任务未被执行。如果发现差异,anacron
将开始执行那些未完成的crontab
任务。这样,anacron
在确保计划任务顺利执行的同时,也避免了因系统关闭导致任务遗漏的情况发生。
anacron与/etc/anacrontab
anacron每小时被主动执行一次的文件放在/etc/cron.hourly下
[root@chenshiren ~]# cat /etc/cron.hourly/0anacron
#!/usr/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
online=1
for psupply in /sys/class/power_supply/* ; do
if [ `cat "$psupply/type" 2>/dev/null`x = Mainsx ] && [ -f "$psupply/online" ]; then
if [ `cat "$psupply/online" 2>/dev/null`x = 1x ]; then
online=1
break
else
online=0
fi
fi
done
if [ $online = 0 ]; then
exit 0
fi
/usr/sbin/anacron -s
# 其实仅是执行了anacron -s的命令
anacron语法
[root@chenshiren ~]# anacron [-sfn] [job] ..
[root@chenshiren ~]# anacron -u [job]..
选项:
-s :开始连续地执行各项任务(job),会根据时间记录文件的数据判断是否执行
-f :强制执行,而不去判断时间记录文件的时间戳
-n :立刻执行未执行的任务,而不延迟等待时间
-u :仅更新时间记录文件的时间戳
job:由/etc/anacrontab定义的各项任务名称
/etc/anacrontab的内容
[root@chenshiren ~]# 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
# 天数 延迟时间 工作名称定义 实际要执行的命令串
# 天数单位天 延迟单位为分钟 任务名称定义可以自定义 命令串则通常与crontab的设置相同
[root@chenshiren ~]# more /var/spool/anacron/*
::::::::::::::
/var/spool/anacron/cron.daily
::::::::::::::
20240322
::::::::::::::
/var/spool/anacron/cron.monthly
::::::::::::::
20240320
::::::::::::::
/var/spool/anacron/cron.weekly
::::::::::::::
20240320
# 上面则是三个任务名称的时间记录文件以及记录的时间戳
anacron的执行流程应该是:(以cron.daily为例)
- 由/etc/anacrontab分析到cron.daily这项任务名称的天数为1天
- 由 /var/spool/anacron/cron.daily 取出最近一次执行 anacron 的时间戳
- 由上个步骤与目前的时间比较,若差异天数为1天以上(含1天),就准备执行命令
- 若准备执行命令,根据/etc/anacrontab 的设置,将延迟5分钟+3 小时(看START HOURS
RANGE 的设置)。 - 延迟时间过后,开始执行后续命令,即【run-parts /etclcron.daily】这串命令。
- 执行完毕后,anacron 程序结束。
如此一来,放置在/etc/cron.daily/内的任务就会在一天后一定会被执行,因为anacron是每一小时被执行一次
crond与anacron的关系
- crond会主动地获取/etc/crontab、/var/spool/cron/*、/etc/cron.d/* 等配置文件,并根据【分、时、日、月、周】的时间来设置去配置各项计划任务
- 根据/etc/cron.d/0hourly的设置,主动去/etc/cron.hourly/目录下,执行所有在该目录下的执行文件
- 因为/etc/cron.hourly/0anacron,这个脚本文件的缘故,主动地每小时执行anacron,并调用/etc/cron.monthly/内的执行文件,以执行固定周期需要执行的命令
如果一个任务放在/etc/crontab
中,一旦它过期就会被视为错过执行,不会重新执行。但如果这个任务被放置在/etc/cron.weekly/
目录下,那么这个任务几乎可以确定会在一周内执行一次。如果你关机超过一周,那么一旦系统开机后的数小时内,这个任务会被anacron
主动执行,这是因为/etc/anacrontab
中进行了相应的配置。
【crontab】和【at】都是【定时】去执行,过了时间就过了,不会重新来一遍,