17

你真的懂 Crontab 吗?

 4 years ago
source link: https://www.tuicool.com/articles/uU3qemz
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

7N7B3eE.jpg!web

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)共同来制定的。如果这两个值都是受限制(比如:不是 *)的话,那么命令将会在日期或者周任意一个符合的日子执行。

c rontab 的标准就是这样,你觉得奇怪也是没有办法的;文档也说的清楚,想错的同学愿赌服输哈。相信 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在日子的确定上是采用日期和星期 的关系。那下一步就是找到代码里面这两个值是如何设定的。

BVfER3z.jpg!web

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

vm2aYru.jpg!web

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

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

JJ3QV3Q.jpg!web

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

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

mMZBbyM.jpg!web

mYjEjav.jpg!web

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK