# 循环执行的例行性工作排程
at 仅执行一次,循环执行则是由 cron(cribd) 这个系统服务来控制的。该系统服务是默认启动的,同时也提供了例行性工作排程的指令 crontab。
# 使用者的设置
同样,为了安全考虑, crontab 指令也可以限制使用者账户:
/etc/cron.allow
:在该文件中的用户才可以执行/etc/cron.deny
:在该文件中的用户,不能执行
一般保留一个文件来控制,系统是默认保留 /etc/cron.deny
,将禁止执行 crontab 的账户写入该文件,一行一个
当使用 crontab 指令建立工作后,会被记录到 /var/spool/cron/
中去,而且是以账户来作为判断的。比如:mrcode 使用 crontab 后,他的工作会记录到 /var/spool/cron/mrcode
文件中,但是请注意,不要使用 vi 直接编辑该文件,因为可能由于输入语法错误,会导致无法执行 cron 。
另外 cron 执行的每一项工作都会被记录到 /var/log/cron
这个登录文件中,所以该日志文件,也可以在一定程度上检查一下是否有异常的执行,比如木马定时执行
# crontab 语法
crontab [-u username] [-l | -e | -r]
选项与参数:
-u:只有 root 才能进行该任务,帮其他使用者建立/移除 crontab 工作排程
-e:编辑 crontab 的工作内容
-l:查询 crontab 的工作内容
-r:移除所有的 crontab 的工作内容,若只删除一项,则使用 -e 编辑
2
3
4
5
6
7
# 范例 1:用 mrcode 身份在每天的 12:00 发信给自己
[mrcode@study ~]$ crontab -e
no crontab for mrcode - using an empty one
# 会进入 VI 的编辑画面,每一行都是一个工作
# 分 时 日 月 周 后面的则是指令串
0 12 * * * mail -s "at 12:00" mrcode < /home/mrcode/.bashrc
crontab: installing new crontab
2
3
4
5
6
7
8
9
每一行是一个工作,共有 6 个字段
代表意义 | 分钟 | 小时 | 日期 | 月份 | 周 | 指令 |
---|---|---|---|---|---|---|
数字范围 | 0-59 | 0-23 | 1-31 | 1-12 | 0-7 | 指令串 |
特别注意:周的数字 0 或 7 都代表「星期天」,下面有一些辅助字符
特殊字符 | 含义 |
---|---|
星号 * | 任何时刻 |
逗号 , | 表示分隔时段。比如 3:00 和 6:00 执行,那么 0 3,6 * * * command 第二栏中用逗号分隔,表示 每天的 3 点和 6 点都执行 |
减号 - | 表示一段时间范围内。比如 8 点到 12 点之间,每小时的 20 分都执行一次,20 8-12 * * * command |
斜线 /n | n 表示数字,每隔 n 单位间隔。比如每五分钟执行一次,*/5 * * * * command ,还可以写成 0-59/5 也是在这个范围类,每 5 分钟执行一次 |
下面进行练习,注意下,下面的练习需要使用 mrcode 这个账户来,后续的动作才能够搭配起来(可能和教学内容有关系吧,不同身份间的)
# 范例 1:假如你女朋友生日是 5.2,要在 5.1 23:59 发一封信给她,这封信的内容已经卸载 /home/mrcode/lover.txt 中了
crontab -e
59 23 1 5 * mail kiki < /home/mrcode/lover.txt
# 范例 2:每 5 分钟执行一次 `/home/mrcode/test.sh`
*/5 * * * * sh /home/mrcode/test.sh
2
3
4
5
6
crontab 每个人都有一个文件存在于 /var/spool/cron/
目录中,指令下达时,最好使用绝对路径
# 范例 3:在每周 5 下午 4:30 告诉你朋友,周 6 的聚会会准时去
30 16 * * 5 mail friend@server.name < /home/mrcode/friend.txt
2
# 查询已经存在的
[mrcode@study ~]$ crontab -l
59 23 1 5 * mail kiki < /home/mrcode/lover.txt
*/5 * * * * sh /home/mrcode/test.sh
30 16 * * 5 mail friend@server.name < /home/mrcode/friend.txt
# 移除工作,只移除一个的话,必须使用 crontab -e 手动删除一行
# 如果是全部移除的话 -r 参数
[mrcode@study ~]$ crontab -r
[mrcode@study ~]$ crontab -l
no crontab for mrcode
2
3
4
5
6
7
8
9
10
11
12
# 系统的配置文件:/etc/crontab、/etc/cron.d/*
crontab -e
是针对使用者的 cron 来设计的,如果是系统的定时任务,则是编辑 /etc/crontab
文件来配置的,crontab -e
指令是 /usr/bin/crontab
基本上 cron 服务最低频率是分钟,所以 cron 每分钟去读一次 /etc/crontab
与 /var/spool/cron/*
内容,因此修改完文件内容后,等待下一分钟就可以生效了,但是还有一种情况是因为某些原因或则是其他的 Unix 系统中,crontab 是读入到内存中的,所以编辑文件后,并不会立即生效,如果是这种情况,重启 crond 服务就好了 systemctl restart crond
# /etc/crontab
[root@study ~]# cat /etc/crontab
SHELL=/bin/bash # 使用哪种 shell 接口
PATH=/sbin:/bin:/usr/sbin:/usr/bin # 执行文件搜索路径
MAILTO=root # 若有额外 STDOUT 以 email 将数据发送给谁
# 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
其他的内容则和 crontab -e 中的类似
MAILTO=root
:当/etc/crontab
文件中的工作指令发送错误时或该工作执行结果有 STDOUT/SEDERR 时,会将错误信息或屏幕显示结果发送给谁?默认由系统寄发一封 mail 给 root,不过偶遇 root 无法在客户端中以 POP3 之类的软件收信,这里一般可以写一个邮箱PATH
:指令搜索路径分 时 日 月 周 身份 指令 七个字段的设置
这里比
/etc/crontab
多了一个 身份字段。由于使用者自己的 crontab 并不需要指令身份,但是/etc/crontab
里面是需要的,如果不指定则默认以 root 身份
# crond 服务读取配置文件的位置
一般来说 ,crond 预设有三个地方会有执行脚本配置文件:
/etc/crontab
:系统级/etc/cron.d/*
:系统级/var/spool/cron/*
:与使用者有关
[root@study ~]# ls -l /etc/cron.d
total 12
-rw-r--r--. 1 root root 128 Aug 9 2019 0hourly
-rw-r--r--. 1 root root 108 Aug 6 2019 raid-check
-rw-------. 1 root root 235 Aug 9 2019 sysstat
# 书上说有 4 个文件,这里少了一个 unbound-anchor 的文件
[root@study ~]# 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
2
3
4
5
6
7
8
9
10
11
12
13
cron.d 目录下存放的是 crontab 的配置文件脚本,一般来说,你想要自己开发新的软件,该软件要拥有自己的 crontab 定时指令时,就以如上 0hourly 文件的方式,放置到该目录下
TIP
举例来说 cron.d 目录的使用场景;开发了一个虚拟化教室的软件,该软件需要定时清除一些垃圾防火墙规则,那么编写一个配置文件 /etc/cron.d/newfile
,如果将来该软件升级,直接覆盖之前的文件即可,比手动去分析 /etc/crontab 要方便
/etc/cron.d/0hourly
文件中,配置的是 每个整点 1 分的时候会执行 run-parts /etc/cron.hourly
[root@study ~]# type run-parts
run-parts is /bin/run-parts
2
会发现,run-parts 是一个 shell 脚本文件,该脚本的工作内容大概是: 5 分钟左右选一个时间来执行 /etc/cron.hourly
目录内的所有执行文件,因此,放在 /etc/cron.hourly
的文件,必须是能被直接执行的指令脚本
也就是说,除了时分日月周加上指令路径的 crond 配置文件之外,也可以把你的 sh 脚本放在 /etc/cron.hourly
目录下,该目录下的文件,将在每小时 1 分钟后 5 分钟内,随机选一个时间点来执行
[root@study ~]# ls -d /etc/cron.*
/etc/cron.d /etc/cron.daily /etc/cron.deny /etc/cron.hourly /etc/cron.monthly /etc/cron.weekly
2
3
除了 cron.hourly 之外,还有 monthly、weekly、deny 目录,分别代表了每月、每周、每日执行一次,这三个目录与 hourly 不一样,他们三个是由 anacron 执行的,而 anacron 的执行方式是放在 /etc/cron.hourly/0anacron
里面的,与前几代 anacron 是单独的 service 不太一样(后续讲解,笔者猜测前几代的 anacron 是一个系统服务,而这里是使用定时任务来达成的)
# 小结
个人化的行为使用
crontab -e
:由于/etc/crontab
是大家都能够读取的权限,放在这个文件中就没有隐私了系统维护管理使用
vim /etc/crontab
:如果是系统的重要工作,为了自己管理方便和追踪,建议写入该文件中固定每小时、每日、每周、每天执行的特别工作
如果与系统维护有关,还是建议放到
/etc/crontab
中集中管理较好。如果想要偷懒,这个几个快捷的目录能满足的话,就放到这些目录中去
# 一些注意事项
防止所有任务都在同一个时间点执行,分散时间点,让系统资源更好的被利用,有以下几个点:
资源分配不均的问题
最严重的问题是系统资源分配不均的问题,举个例子,检测主机流量的信息包括:
- 流量
- 区域内其他 PC 的流量检测
- CPU 的使用率
- RAM 使用率
- 在线人数事实检测
如果每个流程都在同一个时间启动的话,那么在某个时间段,系统会变得相当频繁,所以需要分别错开他们执行时间
取消不要的输出项目
有一个困扰是:当有执行结果或执行中有输出的数据时,该数据会 mail 给 MAILTO 的设置账户,那么当一个任务一直出错(例如 DNS 的检查中,当 DNS 上层主机挂掉,那么你就会一直受到错误信息),想要不看到这些错误的邮件,就可以使用数据重导向将输出结果输出到
/dev/null
中安全的校验
很多时候被植入木马都是以定时任务的方式来植入的,可以检查 /var/log/cron 的内容来检查是否有异常的定时任务运行记录(比如一个你没有见过的定时任务)
周与日月不可同时并存