目录

介绍

[root@ ~]# 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

在此文件中定义了3个变量,其中一个是PATH,该变量极其重要。在最后还给出了任务条目的定义方式:

  1. 每个任务条目分为6段,每段以空格分隔,之所以此处多了user-name段是因为/etc/crontab为系统定时任务文件,而一般定时任务是没有该段的。
  2. 前五段为时间的设定段,分别表示“分时日月周”,它们的定义不能超出合理值范围,第六段为所要执行的命令或脚本任务段。
  3. 在时间定义段中,使用“”表示每单位,即每分钟,每小时,每天,每月,每周几(仍然是每天)。实际上,按man文档中解释,“”表示的是从每个时间段的起始到结尾,也就是全部时间单位的意思。例如在小时上设置*,表示0,1,2,3…22,23的意思。
  4. 每个时间段中,都可以使用逗号“,”来表示枚举,例如定义“0,30,50 * * * *”表示每个时辰的整点、第30分钟和第50分钟都执行该任务。
  5. 每个时间段中,都可以使用“-“定义范围,可以结合逗号使用。如分钟段定义了”00,20-30,50”表示每个时辰的整点、第20到30分钟的每分钟、第50分钟都执行该任务。
  6. 每个时间段中,使用“/“表示忽略时间,如在小时段定义了”0-13/2”表示在“0/2/4/6/8/10/12”点才满足时间定义。常使用“/N”表示每隔多久的意思。例如“00 /2 * * *”表示在每天每隔两小时的整点执行该任务(严格地说是0-23/2,也就是0,2,4,…,22,所以凌晨1点不会执行任务)。
  7. 如果定义的日和周冲突了,则会多次执行(不包括因为*号导致的冲突)。例如每月的15号执行该任务,同时又定义了周三执行该任务,正常无冲突情况下,将在周三和每月15号执行,但如果某月的15号同时是周三,则该任务在此日执行两次。因此,应该尽力避免同时定义周和日的任务。
  8. 命令段(即第6段)中,不能随意出现百分号“%“,因为它表示换行的特殊意义,且第一个%后的所有字符串将当作命令的标准输入。

crond命令的调试

很多时候写了定时任务却发现没有执行,或者执行失败,但因为crond是后台运行的,有没有任何提示,很难进行排错。但是可以让crond运行在前端并进行调试的。

先说明下任务计划程序crond的默认执行方式。

使用下面三条命令启动的crond都是在后台运行的,且都不依赖于终端。

[root@ ~]# systemctl start crond.service
[root@ ~]# service crond start
[root@ ~]# crond
但crond是允许接受选项的。

crond [-n] [-P] [-x flags]
选项说明:
-n:让crond以前端方式运行,即不依赖于终端。
-P:不重设环境变量PATH,而是从父进程中继承。
-x:设置调试项,flags是调试方式,比较有用的方式是test和sch,即"-x test"和"-x sch"。
  :其中test调试将不会真正的执行,sch调试显示调度信息,可以看到等待时间。具体的见下面的示例。

模拟crontab验证脚本

每3秒间隔,时间调整为第2天 0:59:58,调用脚本。

#!/bin/bash
for((i=1;i<=100;i++));
do
    date -s $(date -d "+1 day" +'%F')" 0:59:58"
    sh /some/shell.sh
    date "+%F %T"
    sleep 3
done

crontab调试输出 #从输出sec-to-wait值上可以看出,crond服务每1分钟读取crontab一次,按时间执行相应的CMD任务。可以通过上面的脚本,手动模拟。另外,如果手动调整时间来验证crontab执行的话,最好将时间差保证在1分钟以上。

[root@ ~]# crond -x sch   
debug flags enabled: sch   #
[56092] cron started
log_it: (CRON 56092) INFO (RANDOM_DELAY will be scaled with factor 34% if used.)
log_it: (CRON 56092) INFO (running with inotify support)
[56092] GMToff=28800
log_it: (CRON 56092) INFO (@reboot jobs will be run at computer's startup.)
[56092] Target time=1591837320, sec-to-wait=3
[56092] Target time=1591837380, sec-to-wait=60
[56092] Target time=1591837440, sec-to-wait=60
[56092] Target time=1591837500, sec-to-wait=60
[56092] Target time=1591837560, sec-to-wait=60
[56092], clock jumped   #命令中间手动调整了日期时间。
user [root:0:0:...] cmd="sh /etc/rsync_upload.sh"
[56092] Target time=1583283660, sec-to-wait=42
log_it: (root 58364) CMD (sh /etc/rsync_upload.sh)
....

[56092] Target time=1583974800, sec-to-wait=5
user [root:0:0:...] cmd="sh /etc/rsync_upload.sh"
[56092] Target time=1583974860, sec-to-wait=60
log_it: (root 62920) CMD (sh /etc/rsync_upload.sh)
[56092], clock jumped
...
[56092] Target time=1584579600, sec-to-wait=5
user [root:0:0:...] cmd="sh /etc/rsync_upload.sh"
[56092] Target time=1584579660, sec-to-wait=60
log_it: (root 66646) CMD (sh /etc/rsync_upload.sh)
[56092], clock jumped
[56092] Target time=1584666000, sec-to-wait=5
user [root:0:0:...] cmd="sh /etc/rsync_upload.sh"
[56092] Target time=1584666060, sec-to-wait=60
log_it: (root 67194) CMD (sh /etc/rsync_upload.sh)
[56092], clock jumped
[56092] Target time=1584752400, sec-to-wait=5
user [root:0:0:...] cmd="sh /etc/rsync_upload.sh"
[56092] Target time=1584752460, sec-to-wait=60
log_it: (root 67727) CMD (sh /etc/rsync_upload.sh)
^Clog_it: (CRON 56092) INFO (Shutting down)