欢迎来到无限飞翔,在这里,你会找到许多有趣的技术 : )

你真的懂 Crontab 吗?

开发者头条 178℃

Crontab作为开发人员大家都很清楚是用来做计划任务的。contrab中的 cron 的词根是希腊词 chronic; 而 tab 就是 table 的缩写,crontab 就是一个时间表,编排任务的表格。

Crontab 任务的定义非常的简单,用五个字段来定义任务在什么时候执行。这五个字段中,还可以使用以下表达式:


星号(*):代表所有可能的值,例如month字段如果是星号,则表示在满足其它字段的制约条件后每月都执行该命令操作。

逗号(,):可以用逗号隔开的值指定一个列表范围,例如,“1,2,5,7,8,9”

中杠(-):可以用整数之间的中杠表示一个整数范围,例如“2-6”表示“2,3,4,5,6”

正斜线(/):可以用正斜线指定时间的间隔频率,例如“0-23/2”表示每两小时执行一次。同时正斜线可以和星号一起使用,例如*/10,如果用在minute字段,表示每十分钟执行一次。


crontab的计划任务的编排看起来虽然很简单,但是还是有些一些坑需要注意的。pshu 现在给大家出个题目试试。

写一个crontab 任务,在每年的父亲节00:00执行 echo “happy fathers’ day”。父亲节的定义是每年6月的第3个星期天。


大家的第一个直觉会不会写出这样的 crontab 呢 ?

“0 0 15-21 6 7 echo happy fathers day”


简单分析下:

  • 首先,凌晨执行很简单 0 0 就可以了。

  • 接下来就是第三个星期天了,每个月的第三个星期天可能发生的区间是这个月的第15天到第21天(第一个星期天可能会出现的一个月的第1到第7天之间,以此类推出这个结论),所以用15-21做了日期的限定。

  • 然后是6月,so easy!

  • 最后是礼拜天, week的字段填个 7。

其实这个crontab是错误的,它会在6月份的15-21号的每天执行,以及6月份的每个星期日执行。为什么会这样呢?在crontab 的文档说明里面有一段 Note(注意事项), 要用 `man 5 crontab` 来查看。


Note: The day of a command’s execution can be specified by two fields — day of month, and day of week.  If both fields are restricted (i.e., aren’t *), the command will be run when either field matches the current time.  For example, “30 4 1,15 * 5” would cause a command to be run at 4:30 am on the 1st and 15th of each month, plus every Friday. One can, however, achieve the desired result by adding a test to the command (see the last example in EXAMPLE CRON FILE below).


翻译下主要部分:crontab 命令执行的日子,是由 “日期”(day of month) 和 “周”(day of week)共同来制定的。如果这两个值都是受限制(比如:不是 *)的话,那么命令将会在日期或者周任意一个符合的日子执行。


crontab 的标准就是这样,你觉得奇怪也是没有办法的;文档也说的清楚,想错的同学愿赌服输哈。相信 pshu 的粉丝当中有同学已经知道这个知识点,能分辨这是一个错误的答案,但是正确答案是什么呢?且等我慢慢道来。大家觉得这段文档是不是有点问题,它没有说清楚  “什么是’受限制(restricted)‘”。 搜索了下crontab的文档里面 restricted 这个单词就出现了一次。那crontab如何来界定是否是“restricted“的呢?要回答这个问题只能看源码了。

ubuntu系统下:apt-get source cron,当前目录下获取cron源代码。(其他 linux 发行版代码类似,cron程序最初是由Paul vixie 写的,后来发行版中都是基于 Paul 实现改动的


在 cron.c 文件截图中的9-11行这个巨型的 if 语句中,我们发现 DOW_STAR 或 DOM_STAR 的布尔值就是对应的非restricted的意思。换句话说只要 DOW_STAR 或 DOM_STAR一个为true 的情况,cron在日子的确定上是采用日期和星期的关系。那下一步就是找到代码里面这两个值是如何设定的。


原来系统中的cron程序认为crontab字段的第一个字符为’*’,那么这个字段就处于非限制状态。

那我们父亲节的那个问题的答案应该是 ”0 0 15-21 6 */8”。最后周的定义使用*开头让 crontab 的周进入到非 restricted 状态;同时还要让他只在周日就采用一个非常取巧的方式让它一周每隔 8 天执行,其实还是只要周日执行了。

好了,我们现在算是基本搞懂了 crontab 日期的定义的问题了。当是这样定义显然是有点反直觉的,要不就通过长期的练习修正我们的直觉,要不就是靠工具!是的,pshu 绕了这么一大圈就是为了推荐下最近写的小程序: crontab 助手。

输入你的 crontab 定义,自动帮你翻译成汉语的表达;并计算未来5次 crontab 的执行时间。欢迎大家扫码试用下。如果有bug什么的请发个留言就算发issue了。

父亲节的问题的解答在 “crontab助手”的展示。

喜欢 pshu 的作品欢迎转发点赞喜欢!

转载请注明:无限飞翔 » 你真的懂 Crontab 吗?

喜欢 (0)or分享 (0)