有时我们需要让linux系统按我们指定的时间规则自动的处理某些作业,例如在某个时间点执行某个脚本,周期性的备份数据,这时候就可以制定任务计划了。任务计划分为一次性周期性两类。


一、制定一次性任务计划

   一次性任务计划即执行完一次后就没有了的那种,可以通过at或batch命令生成。计划内容会以文件的形式写入/var/spool/at目录中,一个任务计划对应一个文件,系统的服务进程atd(at daemon)会读取这些文件并执行。某任务执行完毕后,其对应的文件也会被自动删除。

   1、为安全起见,我们通常需要编辑/etc/at.allow(白名单)或/etc/at.deny(黑名单)以允许或拒绝某些特定用户制定任务计划,这两个文件对at和batch命令都适用

     ⑴直接在文件中输入用户名,一行一个用户

     ⑵若这两个文件都不存在,默认只有root可以使用at和batch命令

     ⑶/etc/at.allow若存在但没有任何内容,表示允许的用户为空,意即拒绝所有用户(root除外),同样/etc/at.deny若没有任何内容,则表示放行所有用户。

     ⑷为避免混乱,/etc/at.allow和/etc/at.deny通常不同时使用。但若两者都存在且有矛盾的地方,以/etc/at.allow优先。

   2、at:生成一次性任务计划

     用法:at [option]... [TIME]

     at命令后不能为空,必须接选项或参数

     常用选项:

        -d 作业编号:删除指定的待执行任务,相当于atrm

        -l:显示待执行的任务的列表,相当于atq

        -m:任务执行完成后向用户发送E-mail(默认)

        -c 作业编号:显示指定作业的实际内容

     任务计划创建格式:

        at TIME

        > COMMAND1

        > COMMAND2

        ...

        > 按Ctrl+D结束,结束符为EOT

        TIME格式:            

           HH:MM  如14:30

           HH:MM YYYY-MM-DD  如14:30 2015-10-07

           HH:MM[am|pm] [Month] [Date]  如02:30pm October 07

           HH:MM[am|pm] + number [minutes|hours|days|weeks]  如14:30 + 2 weeks

           now + #UNIT     如now + 5minutes

           noon,midnight,teatime,tomrrow

      其它命令:

         atq:查看待执行任务列表,相当于at -l

         atrm:删除指定作业,相当于at -d

      注:任务作业执行后,若有错误或标准输出,则会以邮件形式告知提交者。可重定向至其他地方或干脆丢弃(> /dev/null)

[root@localhost ~]# at now+2minutes  # 两分钟后执行
at> tail -2 /etc/group
at> <EOT>
job 6 at 2015-10-07 23:36
[root@localhost ~]# mail   # 上述命令执行完后,root已收到邮件
Heirloom Mail version 12.4 7/29/08.  Type ? for help.
"/var/spool/mail/root": 1 message 1 new
>N  1 root                  Wed Oct  7 23:36  15/526   "Output from your job        6"
& 1
Message  1:
From root@localhost.localdomain  Wed Oct  7 23:36:00 2015
...
wittgenstein:x:500:
tesla:x:501:

& q
[root@localhost ~]# at 07:30
at> echo "Good morning" > /dev/pts/0  # 将结果重定向至终端屏幕而非以邮件形式告知root
at> <EOT>
job 8 at 2015-10-08 07:30
[root@localhost ~]# at tomorrow  # 明天这个时候执行(即时隔24小时)
at> rm -f /home/tesla/passwd
at> <EOT>
job 9 at 2015-10-08 23:43
[root@localhost ~]# at -l    # 显示待执行任务
8	2015-10-08 07:30 a root   # 第4段表示作业队列
9	2015-10-08 23:43 a root
[root@localhost ~]# atrm 9   # 删除9号任务
[root@localhost ~]# atq      # 显示待执行任务
8	2015-10-08 07:30 a root
[root@localhost ~]# at -c 8  # 查看8号任务的内容
#!/bin/sh
# atrun uid=0 gid=0
# mail root 0
...
echo "Good morning" > /dev/pts/0

marcinDELIMITER6e7b2aa1

   3、batch

     batch不同于at的地方仅在于其所生成的任务计划是在系统空闲时执行的,故batch命令后不能指定时间。

[root@localhost ~]# batch
at> echo "hello"
at> <EOT>
job 10 at 2015-10-07 23:44


二、制定周期性任务计划

    周期性任务计划是由crond(cron daemon)这个系统服务来控制的。与atd服务一样,crond也是默认启动的工作于后台的守护进程。crond执行的每一项任务都会被记录到/var/log/cron这个日志文件中。

    周期性任务计划分两类:

      ①系统cron:定义在/etc/crontab文件中,直接编辑即可

      ②用户cron:定义在/var/spool/cron目录中,每个用户都有一个与用户名同名的文件(/var/spool/cron/USERNAME),其功能类似于/etc/crontab,使用crontab命令生成

    系统通常自带cron服务程序和crontab命令,若没有,可使用如下命令安装:

      yum -y install vixie-cron   #cron服务程序包

      yum -y install crontabs   #crontab程序包

    系统cron和用户cron的制定语法只存在细微差别,现主要说明一下用户cron的创建

   1、用户周期性任务计划

     ⑴与at一样,我们也可以设置白名单(/etc/cron.allow)或黑名单(/etc/cron.deny)来限制使用crontab的用户,再次建议,这两个文件保留一个即可。

     ⑵使用crontab命令创建用户cron

        用法:crontab [-u username] [-elr]

        选项:

          -u:管理员可为其他用户创建任务

          -e:打开编辑页面定义任务

          -l:列出已经定义的所有任务

          -r:移除所有任务

        crontab -e打开编辑页面后,一行一个任务进行编辑,每行包括6段,前5段为时间,最后一段为要执行的命令,格式如下:

          分钟 小时 日 月 周几 命令

          例如 0 0 7 10 * echo "happy birthday" | mail -s "blessing" tesla          

          时间位:

            *:表示任何时刻都接受的意思,所有时间段位上不能同时为*

            数字:表示具体某一小时某一分钟等,如 8 8 8 8 * 表示每年的8月8日8时8分

            ,:表示分隔时段,表示一段时间范围,如 8 9,13  *  *  * 表示每天9:08和13:08

            */#: 在对应的时间位的有效取值上每#一次,如 */8  *  *  *  * 表示每8分钟一次

            -:某个时间位上的连续区间,如 10-50/8  *  *  *  * 表示第10分和第50分之间每8分钟一次

         crontab的最小单位是分钟,那么如何实现秒级别的任务呢?

            例:每10秒输出一次rose

              * * * * * for i in {0..5};do echo "rose";sleep 10;done

         注意:%在crontab中有特殊意义,如果在crontab的用户命令中要用到%,则要转义,使用\%格式  

      ⑶与atd一样,crond在执行完任务作业后,若有错误或标准输出,也会以邮件形式通知提交者。

      cron中的环境变量问题

        cron守护进程在执行任务时默认遵循的是cron环境变量定义,而cron环境变量定义得比较简单,尤其是PATH变量(cron里默认是/usr/bin:/bin),故有时候会出现无法找到命令的情况,如下图。因此,我们应使用命令的绝对路径或者在任务之前自定义变量;时间段后如果接的是脚本,在脚本中最好也自定义PATH变量或添加source /etc/profile和source $HOME/.bash_profile

[tesla@localhost ~]$ crontab -e
*/2 * * * * ifconfig   # 在打开的页面中输入这一行任务
no crontab for tesla - using an empty one
crontab: installing new crontab
[tesla@localhost ~]$ crontab -l   # 查看任务列表
*/2 * * * * ifconfig
[tesla@localhost ~]$ mail
Heirloom Mail version 12.4 7/29/08.  Type ? for help.
"/var/spool/mail/tesla": 1 message 1 new
>N  1 Cron Daemon           Thu Oct  8 19:02  22/791   "Cron <tesla@localhost> ifconfig"
& 1
Message  1:
...
From: root@localhost.localdomain (Cron Daemon)
To: tesla@localhost.localdomain
Subject: Cron <tesla@localhost> ifconfig
Content-Type: text/plain; charset=UTF-8
Auto-Submitted: auto-generated
X-Cron-Env: <LANG=en_US.UTF-8>
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/home/tesla>
X-Cron-Env: <PATH=/usr/bin:/bin>   #注意这一行,cron预设的PATH变量
X-Cron-Env: <LOGNAME=tesla>
X-Cron-Env: <USER=tesla>
Date: Thu,  8 Oct 2015 19:02:01 +0800 (CST)
Status: R

/bin/sh: ifconfig: command not found   # 提示找不到命令

[tesla@localhost ~]$ which 'ifconfig'
/sbin/ifconfig    # 显示ifconfig命令在/sbin目录下,cron默认PATH变量中并不包含
[tesla@localhost ~]$ echo $PATH    # 查询当前用户PATH变量
/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/tesla/bin
[tesla@localhost ~]$ crontab -e
SHELL=/bin/bash
JAVA_HOME=/usr/java/latest
PATH=$JAVA_HOME:/bin:/sbin:/usr/bin:/usr/sbin

30 00 * * * /scripts/backup.sh &> /dev/null

[tesla@localhost ~]$ crontab -r   # 删除所有任务
[tesla@localhost ~]$ crontab -l
no crontab for tesla
[tesla@localhost ~]$ su - root
Password: 
[root@localhost ~]# ls /var/spool/cron   # 在root用户下查看有哪些用户cron
tesla
[root@localhost ~]# crontab -u tesla -r  # 管理员可操作其他用户cron
You have new mail in /var/spool/mail/root
[root@localhost ~]# crontab -u tesla -l
no crontab for tesla


   2、系统周期性任务计划

     系统cron是直接在/etc/crontab文件中编辑的,该文件开头部分已预先设置了一些环境变量,如下,与用户cron不同的地方在于时间段和命令段之间多个一个用户段,此段必须指定,系统cron默认是以root身份进行的。

[root@localhost ~]# cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/

# 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  # 时间段与命令段之间多了一个用户段


   3、anacron

      crontab的补充机制,检查有没有过去一个有效周期未曾执行的任务,如果有,在开机后的指定时间点执行一次。


三、制定周期性任务实例:

   1、每4小时执行一次对/etc/目录的备份,备份至/backup目录中,保存的目录名为etc-当前时间(以类似于2015071004的格式)

       0 */4 * * * [ -d /backup ] || madir /backup;/bin/cp -a /etc /backup/etc-$(date +"\%Y\%m\%d\%H")

   2、每周3,5,7备份/var/log/messages 文件至/backup/message_logs/目录中,保存的文件名为messages-当前时间

       0 2 * * 3,5,7 /bin/cp -a /var/log/messages /backup/message_logs/messages-$(date +"\%Y\%m\%d\%H") 

   3、每天每两小时取当前系统/proc/meminfo中的以S开头的信息保存至/status/memory.txt中

       0 */2 * * * /bin/grep -i '^S' /proc/meminfo >> /status/memory.txt

   4、工作日的工作时间内,每小时执行一次echo "howdy"

       0 8-17 * * 1-5 echo "howdy"