Linux 定时任务

参考文章:

Linux下的crontab定时执行任务命令详解
Linux中的定时任务crontab

 

  • 在LINUX中,周期执行的任务一般由cron这个守护进程来处理[ps -ef|grep cron]。cron读取一个或多个配置文件,这些配置文件中包含了命令行及其调用时间。
  • cron的配置文件称为“crontab”,是“cron table”的简写。

 

一. cron服务

cron是一个linux下 的定时执行工具,可以在无需人工干预的情况下运行作业。
service crond start    //启动服务
service crond stop     //关闭服务
service crond restart  //重启服务
service crond reload   //重新载入配置
service crond status   //查看服务状态 

 

二. cron在3个地方查找配置文件

①/var/spool/cron/ 这个目录下存放的是每个用户包括root的crontab任务,每个任务以创建者的名字命名,比如tom建的crontab任务对应的文件就是/var/spool/cron/tom。一般一个用户最多只有一个crontab文件。

②/etc/crontab 这个文件负责安排由系统管理员制定的维护系统以及其他任务的crontab

③/etc/cron.d/ 这个目录用来存放任何要执行的crontab文件或脚本。

 

三. 权限

crontab权限问题到/var/adm/cron/下一看,文件cron.allow和cron.deny是否存在
用法如下: 
1、如果两个文件都不存在,则只有root用户才能使用crontab命令。 
2、如果cron.allow存在但cron.deny不存在,则只有列在cron.allow文件里的用户才能使用crontab命令,如果root用户也不在里面,则root用户也不能使用crontab。 
3、如果cron.allow不存在, cron.deny存在,则只有列在cron.deny文件里面的用户不能使用crontab命令,其它用户都能使用。 
4、如果两个文件都存在,则列在cron.allow文件中而且没有列在cron.deny中的用户可以使用crontab,如果两个文件中都有同一个用户,
以cron.allow文件里面是否有该用户为准,如果cron.allow中有该用户,则可以使用crontab命令。

 

四. cron的具体使用

  • 使用命令crontab -e即可编辑crontab,在里面添加需要的定时任务。用户的定时任务文件为 /var/spool/cron/用户名 ,crontab -e命令将相当于vim /var/spool/cron/用户名。

 

1. 如何写crontab

  • crontab中每一行代表一个任务,每个任务由周期和任务名组成。如下形式   

59 23 10 5 2014 /home/root/tesh.sh

#分 时 日 月 年 |<-------命令串------->|

 

        表示2014年5月10日23点59分,执行/home/root下的tesh.sh脚本。

  • 时间周期中可以使用一些辅助字符,如:
    *    表示任何时刻都可以
    ,  若有多个时刻,用逗号分隔
    -     表示一个时刻到另一时刻之间的时间段
    /n   表示每过n个时间单位
  • 比如,*/10 3-6 10,11 * * /home/root/tesh.sh 就表示 每年每月的10号和11号,3点到6点之间,每过10分钟执行一次tesh.sh

  • Cron表达式是一个字符串,字符串以4或5个空格隔开,分为5或7个域,每一个域代表一个含义,Cron有如下两种语法格式: 
    Minutes Hours DayofMonth Month DayofWeek Year或 
    Minutes Hours DayofMonth Month DayofWeek

    每一个域可出现的字符如下: 
    Minutes:可出现", - * /"四个字符,有效范围为0-59的整数 
    Hours:可出现", - * /"四个字符,有效范围为0-23的整数 
    DayofMonth:可出现", - * / ? L W C"八个字符,有效范围为1-31的整数 
    Month:可出现", - * /"四个字符,有效范围为1-12的整数或JAN-DEc 
    DayofWeek:可出现", - * / ? L C #"四个字符,有效范围为1-7的整数或SUN-SAT两个范围。1表示星期天,2表示星期一, 依次类推 
    Year:可出现", - * /"四个字符,有效范围为1970-2099年

 

  • 每一个域都使用数字,但还可以出现如下特殊字符,它们的含义是: 
    ①*:表示匹配该域的任意值,假如在Minutes域使用*, 即表示每分钟都会触发事件。
    ②?:只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用*,如果使用*表示不管星期几都会触发,实际上并不是这样。 
    ③-:表示范围,例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次 
    ④/:表示起始时间开始触发,然后每隔固定时间触发一次,例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次. 
    ⑤,:表示列出枚举值值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。 
    ⑥L:表示最后,只能出现在DayofWeek和DayofMonth域,如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。 
    ⑦W:表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。例如:在 DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份 
    ⑧LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。 
    ⑨#:用于确定每个月第几个星期几,只能出现在DayofMonth域。例如在4#2,表示某月的第二个星期三。

 

2. crontab注释

  • 在crontab中,#代表了注释,注释的存在,能够简化crontab的一些复杂操作。

 

  • 比如,如果有一个任务test.sh,每天都需要执行,每过10分钟执行一次,我们可以写成 */10 * * * * tesh.sh。现在有新要求,每天1点到1点10分不能执行,其余时间照旧。

    一种写法就是:将它拆成多条crontab,比如每天2点到0点执行,每天0点到1点执行,每天1点10分到2点执行。三条语句。这种方法的问题就是,如果再来新的要求呢,比如在此基础之上,每天8点到8点10分不能执行,这又怎么处理,写更多的crontab任务吗?

    另一种比较好的解决方案是:写一个run.sh脚本,每10分钟执行一次,首先判断当前时间是否是在1点到1点10分之间,如果不是,就执行tesh.sh,如果是,可以sleep10分钟。

    第三种非常好的方案就是利用注释。我们可以在1点时,将tesh.sh任务给注释掉,在1点10分,将tesh.sh任务的注释消除。要实现这种想法,需要使用sed命令。可以在crontab里面这样写:

#每隔10分钟执行一次
*/10 * * * * tesh.sh
 
#每天1点钟,将命令注释掉
0 1 * * * sudo sed -i 's%(*/10 * * * * tesh.sh)%#1%' /var/spool/cron/用户名
 
#每天1点零10分,将被注释的命令恢复
10 1 * * * sudo sed -i 's%(^##*)(*/10 * * * * tesh.sh)%2%' /var/spool/cron/用户名
 

  • sed -i表示直接修改文件内容,之后的动作必须用单引号括上,单引号之后的是文件。单引号内部s表示替换,s之后的%是分隔符,代替默认的/分隔符,括弧表示将括号里面的内容保存下来,标记为1,#表示把注释扩展到下一个换行符以前,1表示选取括号中的内容。
  • 这里出现了众多的反斜杠,都是用来做转义的,否则会被解析。
  • %前面的反斜杠是用来转义crontab的,crontab中会将%解析成换行符。括弧和*前的反斜杠是因为sed会解析它们。
  • 如果不是在crontab中,这个命令可以写成 sed -i 's%*/10****tesh.sh*/10****tesh.sh%#1%'  file

 

3. crontab的调试方式

  • 如果crontab不执行,我们可以使用 sudo vim /var/spool/mail/用户名查看系统发给用户的mail,可以通过时间点,来找出执行失败的原因。