在这一章当中我们讲述Linux任务计划以及周期性任务的执行。

一、任务计划

  我们此前说过一些备份的知识,假如在某种场景当中需要做备份,例如MySQL、Redis以及mongodb等数据管理系统或相关服务及程序,对于那些数据而言,如果要做周期备份的话,则必然就要用到该功能。在例如,对于公司来讲,最关键的就是数据,而不是系统,因为只要数据还在,则可以快速建立一个系统,而如果数据不在,则无法建立出系统。所以数据备份是至关重要的一件事情。
  数据备份通常每天一次,甚至于每小时一次,那么这种任务我们就称之为是周期性任务。还有一种就是在凌晨的时候,把某个目录一次性给复制到另一台备份主机,如果这是周期性质的话,每天做一遍,那这就是周期性任务,如果说是为了每个需要,只是做一次的话,那这种就是任务计划。
  他俩的本质没有太大的差别,有一些区别的就是一种在未来的某一个时间点执行一次任务,另一种就是重复或周期性运行某任务,总结如下:

   未来的某时间点执行一次某任务:at, batch
   周期性运行某任务:crontab
	  执行结果:会通过邮件发送给用户;

  对于Linux来讲,周期性任务是要经常执行的,而单一的任务计划也是需要在未来的某一时刻进行运行,如果用户没有登录在线的话,一旦任务执行完成,会通过邮件来发送给用户。这种电子邮件并不需要连接到互联网中,而是在本地系统上会启用一个邮件服务,这个服务只能用于本地用户与用户之间彼此传递信息。这种用户不在线时将执行结果通过邮件发送给用户,是一种非常行之有效的方式,这种邮件服务并不是并不是互联网那种公开的服务,而是仅仅保证本地用户在下一次登录时的,该邮件执行的是推送消息结果的服务,所以说这个服务只能用于本机上来相互传递邮件消息。但如果要想工作起来,需要依赖两点,第一就是要启动该邮件服务,第二点就是有该用户临时的收发位置,不过好在CentOS中,默认都是开启本地邮件服务,我们可以用netstat或者ss命令来查看某个服务25号端口是否开启。

# ss -tnl
State      Recv-Q Send-Q              Local Address:Port           Peer Address:Port                               
LISTEN        0   100                   ::1:25                :::*

  可以看出,25号端口处于监听开启状态,如果该端口开启的话,就说明服务运行正常。那么查看某个端口的命令如下:

   # netstat -tnlp
   # ss -tnl

1.1 mailx命令

  为了能查看任务往来的通信结果及情况,我们需要前提掌握关于邮件的收发命令,否则无法判断该任务计划到底执行与否,所以我们来查看本地电子邮件服务。

   本地电子邮件服务:
	 smtp:simple mail transmission protocol
	 pop3:Post Office Protocol
	 imap4:Internet Mail Access Protocol

  以上的几种协议了解即可,我们现在主要掌握的是如何在本地主机上收发邮件,其该命令为mail命令。它能够收发互联网邮件,是一个很强大的文本行界面的工具,它是一种用户收发邮件的一种工具程序,我们称之为MUA,不管是WEB界面上的还是字符界面上的,我们都称之为用户收发的一种工具程序。
  要想使用mail或mailx命令收发邮件的话,方法是很简单的,该命令的格式为:

   mail命令:
	 mailx - send and receive Internet mail
		
		 MUA: Mail User Agent,用户收发邮件的工具程序;
		
		 mailx [-s 'SUBJECT'] username[@hostname]

  比如说,写一个邮件发送给abc3用户,指明主题为'hello wuhuang!'

# mail -s 'hello wuhuang' abc3

  我们看到,底下有一行空白处,这是系统等待用户输入内容后,按.进行单独一行发送,邮件发送完成。所以说该命令是这样的。

# mail -s 'hello wuhuang' abc3
wuhuangwansui!
.
EOT

  之后我们切换abc3,使用mail命令查看邮件是否存在,需要注意的是,mail不带任何选项是收邮件及查看邮件的,N表示为新邮件,按相关序号就能进行查看,那么看完之后按q键退出。

# su - abc3
$ mail
Heirloom Mail version 12.5 7/5/10.  Type ? for help.
"/var/spool/mail/abc3": 1 message 1 new
>N  1 root                  Sat Mar 10 19:43  18/580   "hello wuhuang"
& 1
Message  1:
From [email protected]  Sat Mar 10 19:43:18 2018
Return-Path: 
X-Original-To: abc3
Delivered-To: [email protected]
Date: Sat, 10 Mar 2018 19:43:17 +0800
To: [email protected]
Subject: hello wuhuang
User-Agent: Heirloom mailx 12.5 7/5/10
Content-Type: text/plain; charset=us-ascii
From: [email protected] (root)
Status: R

wuhuangwansui!

& q
Held 1 message in /var/spool/mail/abc3
You have mail in /var/spool/mail/abc3

  我们还可以自动给邮件给予正文,我们刚才是使用mail命令下的交互式模式中写出正文,只要是从标准输入获取的数据,我们可以使用管道以及重定向来解决自动给予正文的问题。比如我们使用abc3用户给root发送一个文件fatab的内容,标题为‘fstab file’

$ mail -s 'fstab file' root < /etc/fstab

  还有一种是通过管道,比如说使用cat命令来查看fstab文件,通过管道送入mail命令。

$ cat /etc/fstab | mail -s 'fatab files' root

  我们退回到root用户使用mail命令查看。

# mail
Heirloom Mail version 12.5 7/5/10.  Type ? for help.
"/var/spool/mail/root": 2 messages 2 new
>N  1 [email protected]  Sat Mar 10 20:14  29/1153  "fstab file"
 N  2 [email protected]  Sat Mar 10 20:18  29/1154  "fstab files"
&

  那么我们总结一下邮件正文的生成:

			邮件正文的生成:
				(1) 交互式输入;.单独成行可以表示正文结束;Ctrl+d提交亦可。
				(2) 通过输入重定向;
				(3) 通过管道;

  那么我们接下来讲述一下周期性任务,以及讲述一下在未来的某一个时刻执行一次某种任务。

二、at命令

  at的命令用法其实很简单,就是使用at命令跟上一些选项,之后选择在未来的某个时刻执行,其命令格式如下:

   at [OPTION]... TIME

  而TIME的使用格式及方法如下:

    TIME: 
    	HH:MM [YYYY-mm-dd]
    	noon, midnight, teatime
    	tomorrow
    	now+#
	    	UNIT: minutes, hours, days, OR weeks

  比如说一分钟后运行ls命令,输入完成之后,使用Ctrl+d快捷键退出。而任务是可以写入多个的,在未来的某一时刻中同时运行。

# at now+1min 
at> ls
at> 
job 1 at Sat Mar 10 20:48:00 2018

  我们使用mail命令可以查看运行结果。

# mail
>N  3 root                  Sat Mar 10 20:48  28/607   "Output from your job        1"
& 3
Message  3:
From [email protected]  Sat Mar 10 20:48:01 2018
Return-Path: 
X-Original-To: root
Delivered-To: [email protected]
Subject: Output from your job        1
To: [email protected]
Date: Sat, 10 Mar 2018 20:48:01 +0800 (CST)
From: [email protected] (root)
Status: R

admin
admin.txt
anaconda-ks.cfg
Desktop
Documents
Downloads
EOF
httpd-2.4.25.tar.gz
initial-setup-ks.cfg
Music
Pictures
Public
scripts
Templates
Videos

&

  那么我们需要注意的是,当多个用户执行任务管理繁杂时,以队列的形式用来管理,默认为a队列。

   at的作业有队列,用单个字母标识,默认都使用a队列。

  at命令的常用选项如下:

	常用选项:
		-l:查看作业队列,相当于atq;
		-f /PATH/TO/SOMEFILE:从指定文件中读取作业任务,而不用在交互式输入;
		-d:删除指定作业,相当于atrm;
		-c:查看指定作业的具体内容;
		-q QUEUE:指明队列;
	
	注意:作业执行结果是以邮件的形式发送给提交作业的用户;

  那么我们在文件中编写任务,交给at命令在两分钟之后执行,这样的话不需要用户进行交互,步骤如下:

# vim at.tasks
echo "Hello World"
echo "Do you like one you see?"
echo "Boy next door!"

# at -f at.tasks now+2min

2.1 batch命令

  batch和at命令是一样的,但两者不同之处在于batch命令不像at命令一样,指定作业在某个时间运行,而是让系统自行选择,在系统较为空闲的时间去执行指定的任务。也就是说,不用指定时间了,但其它的使用方法与at命令基本相同。

三、周期性任务

  周期性任务计划采用的是cron机制,对于cron而言,必须有一种机制到达某种时间执行将其结果进行提交,这种机制就是一种服务,我们需要这种服务一直出于运行状态,而这种服务一直运行在后台,而这种服务需要检查那些任务该执行,所以说这是需要一种服务程序,始终监听并查看对应的时间点去运行的任务是否符合条件,而后将其运行,这种服务程序,在系统上所依靠的程序包为cronle,提供了crond守护进程及相关辅助工具。

   周期性任务计划:cron
	   服务程序:
		   cronle:主程序包,提供了crond守护进程及相关辅助工具;
	
	   确保crond守护进程(daemon)出于运行状态:
		   CentOS 7
			   # systemctl status crond.service
				   Active: active (running)... ...
		
		   CentOS 6
			   # service crond status
				   ... is running.

  只有以上两种守护进程出于运行状态,我们才能保证其在运行计划中的任务才能可以实现,因此也要像at命令一样,也是需要提交一个或多个任务作业给crond,只不过提交crond作业的方式不同于at,它是需要使用专用的配置文件,该文件有固定的格式,不过不建议使用文本编辑器直接编辑此文件;可使用crontab命令来解决此问题。该命令会自动检查语法错误,一旦发现有什么错误时,会发出提示或直接拒绝提交。
  而cron任务共分为两类,一种是系统cron的任务,是为了系统完成自身的维护任务,另一种是用户cron任务,是为了用户的某个需要来实现的。总结如下:

   向crond提交作业的方式不同于at,它需要使用专用的配置文件,此文件有固定格式,不建议使用文本编辑器直接编辑此文件;要使用crontab命令。
      cron任务分为两类:
           系统cron任务:主要用于实现系统自身的维护;
               手动编辑:/etc/crontab文件;
           用户cron任务:
               命令:crontab命令;

  对于第一种系统任务来讲,我们不需要手动进行编辑,在系统安装的时候,该任务就会创建完成,我们无需指定,但用户cron是我们需要使用的,并且需要遵守该任务的格式即标准。
  我们现在查看一下系统的cron任务的配置文件,该路径在/etc/目录下。

系统cron的配置格式:
    # cat /etc/crontab 
    SHELL=/bin/bash
    PATH=/sbin:/bin:/usr/sbin:/usr/bin
    MAILTO=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
   SHELL:指定shell解释器所运行的脚本或命令;
   PATH:指定某种路径去寻找该命令,不过由于路径太少,可以在写任务时使用绝对路径,或自定义PATH环境变量;
   MAILTO:运行任务的执行结果通过邮件发送给用户,默认为发送给root;

  虽然系统cron配置文件基本不需要更改,或者说很少编辑,但是我们需要了解一下cron文件具体的每一行的解释,记住它的要点。

   注意:
       (1) 每行定义一个cron任务,共7个字段;
           *  *  *  *  * :定义周期性时间;
           user-name:运行任务的用户身份;
           command to be executed:任务
        
       (2) 此处的环境变量不同于用户登录后获得的环境,因此,建议命令使用绝对路径,或者自定义PATH环境变量;
       (3) 执行结果邮件发送给MAILTO指定的用户;

  以上就是系统cron的配置,那么接下来我们说一下用户cron的配置。对于用户cron来讲,没有username这一项了,而用户cron的配置文件的路径在:/var/spool/cron/USERNAME。所以在用户cron当中则不需要用户名这一项了。

用户cron的配置格式:
    SHELL=/bin/bash
    PATH=/sbin:/bin:/usr/sbin:/usr/bin
    MAILTO=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
    # |  |  |  |  |
    # *  *  *  *  *  command to be executed

  我们需要注意的是,系统cron文件和用户cron文件略有区别,其总结如下:

    注意:
        (1) 每行定义一个cron任务,共6个字段;
        (2) 此处的环境变量不同于用户登录后获得的环境,因此,建议命令使用绝对路径,或者自定义PATH环境变量;
        (3) 邮件发送给当前用户;

  那么文件格式大体从以上的框架中进行了解,那么接下来我们如何指定时间点。

3.1 时间表示法

  对于用户cron和系统cron来说,都是通用的,那么如何指定时间点来说,有以下实现机制:

   (1) 特定值:
     给定时间点有效取值范围内的值;
         注意:day of week和day of month一般不同使用;
        
   (2) *
     给定时间点有效取值范围内的所有值:表"每..";找时间点最小的*
     
   (3) 离散取值:,
     在给定的时间点上使用逗号分开多个值即可;
         #,#,#
        
   (4) 连续取值:
     在时间点上使用-连接开头和结束;
         #-#

   (5) 在制定时间点上,定义步长;
        /#:#即步长;
        
        注意:
            (1) 指定的时间不能被步长整除时,其意义将不复存在;
            (2) 最小时间单位为"分钟",想完成"秒"级任务,得需要额外借助于其它机制;
                定义成每分钟任务:而在利用脚本实现在每分钟之内,循环执行多次;

  示例:

    (1) 3 * * * *:每小时执行一次,每次为三分钟;
    (2) 4 3 * * 5:每周执行一次;每周5的4点3分;
    (3) 5 6 7 * *:每月执行一次;每月7号的6点5分;
    (4) 7 8 9 10 *:每年执行一次,每年10月9号8点7分;
    (5) 9 8 * * 3,7:每周三和周日;
    (6) 0 8,20 * * 3,7
    (7) 0 9-18 * * 1-5
    (8) */5 * * * *:每五分钟执行一次某任务;

3.2 crontab命令

  如果某个用户想定义cron任务,我们就可以使用crontab命令就可以了,其命令格式为:

    crontab命令:
        crontab [-u user] [-l | -r |-e][-i]

  该命令选项为:

   -e:编辑任务;
   -l:列出所有任务;
   -r:移除所有任务;即删除/var/spool/cron/USERNAME文件;
   -i:在使用-r选项移除所有任务时提示用户确认;
   -u user:root用户可为指定用户管理cron任务;

  需要注意的是,不能使用vim编辑器来编写任务计划,因为不能检查其语法错误。
  如果你运行的结果没有问题时,可以选择不接收邮件。

   注意:运行结果以邮件通知给当前用户;如果拒绝接收邮件:
      (1) COMMAND > /dev/null
      (2) COMMAND &> /dev/null

  还需要注意一点的是:

   注意:定义COMMAND时,如果命令需要用到%,需要对其转义;但放置于单引号中的%不用转义亦可;