为什么crontab在指定月份和星期几时使用OR?

Ale*_*idt 11 unix linux cron crontab

这是一个着名的"问题",当crontab行包含星期和月中的某一天时,cron使用OR来计算一天来发出命令.例如,如果你写

* * 13 * 5 command
Run Code Online (Sandbox Code Playgroud)

该命令将在每个星期五和每月的第13天执行,而不仅仅是在星期五的第13天.这与其他字段的格式相矛盾(当您编写30 2***时,它将仅在小时和分钟时执行 - 正是您指定的;除了DoW和DoM之外的所有其他字段都相同).

所以我的问题是:这个例外是否有特定的原因?我的意思是,应该有一个理由,但我似乎无法找到它.(相反,我看到互联网中的很多人都希望像其他任何一样对待这些领域 - 使用"AND策略",正好适用于"星期五13"或"5月的第2个星期四"之类的东西.)

Mar*_*ery 13

也许这不是一个足够深刻的“为什么”来满足你——它当然不能满足我——但一个肤浅的答案是“因为标准是这么说的”。

具体来说,POSIX 标准在http://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html中规定:

如果月份或月份中的某一天被指定为元素或列表,并且星期几也被指定为元素或列表,则月份和月份中的某一天星​​期几匹配的任何一天都应为匹配的

(加粗我的)。

我不知道为什么这是标准的要求。有趣的是,似乎连实现 Vixie Cron(Ubuntu 和 MacOS 上使用的 Cron 实现)的 Paul Vixie 也不知道;在cron.c中有这样的评论:

/* the dom/dow situation is odd.  '* * 1,15 * Sun' will run on the
 * first and fifteenth AND every Sunday;  '* * * * Sun' will run *only*
 * on Sundays;  '* * 1,15 * *' will run *only* the 1st and 15th.  this
 * is why we keep 'e->dow_star' and 'e->dom_star'.  yes, it's bizarre.
 * like many bizarre things, it's the standard.
 */
Run Code Online (Sandbox Code Playgroud)

因此,听起来,即使是您可能正在使用的 Cron 的实现者也不知道您的问题的答案比我在本答案的第一段中给出的非解释更深入。


小智 5

回到Vixie cron之后,System V cron中出现了“ wday OR mday”逻辑,但System III或更早版本中没有。

在Paul Vixie编写cron替代人之前,BSD cron就像SysIII及更早的cron。所有5个字段都进行了AND运算。4.4版之后的BSD采用了Vixie cron,使自己更像SysV。

所以不要问(怪罪)Vixie。他只是在克隆SysV。

SysV为什么这样做?我不知道,但我会尝试提供一些线索...

为了尝试了解SysV中发生了什么,它有助于查看源(在-SysIII之前-SVr4 之后)以及新行为的文档:

注意:可以通过两个字段(月中的天和周中的天)来指定天数。如果将两者都指定为元素列表,则都遵守。

(摘录自SunOS 4.1.3手册页。这似乎是SysV-ish。BSDcron在Paul Vixie撰写他的替代书之前从未有过这种行为。)

“两者都遵守”是使用AND和OR的普通布尔表达式的令人困惑的替代。几十年后,它仍在OpenSolaris手册页中:

可以通过两个字段(星期几和星期几)来指定天数。如果指定为元素列表,则两者都遵守。

SysV代码是完整的重写。它的功能之一是长时间没有作业要运行时会长时间睡眠。(较早的cron每分钟都会醒来,并将当前时间与所有作业规范进行比较。)计算功能(next_time)顶部的注释说明:NOTE: this routine is hard to understand.

确实很难理解。这是“查找此crontab行的下一次执行时间”功能,而不是“确定当前时间是否与此crontab行相匹配”功能,因此,即使在这种情况下,即使弄清楚该函数中隐含的匹配规则,也需要花费一些精力既mdaywday是非*,是(month AND hour AND minute AND (mday OR wday))

基于此,再结合文档避免明确告诉我们mday匹配和wday匹配之间的布尔关系的方式,我猜想写新cron的人并没有考虑这些术语。他们考虑的不是5个布尔值的组合(直接对应于中的5个字段struct tm),而是考虑一组4个问题:

  1. 这是正确的月份吗?
  2. 今天正确吗?
  3. 现在是正确的时间吗?
  4. 是正确的分钟吗?

这自然会导致天比较以自己的方式组合在一起,然后再将其他所有内容进行“与”运算。也许SysV cron作者只是做了当时感觉很明显的事情,而没有检查与旧cron的兼容性或思考“每月的第一个星期六”之类的用例。


小智 -3

我在 Unix 服务器上工作,该服务器在 crontab 中使用许多脚本。对于我们来说,能够在应该在一周中的某一天运行的脚本上指示具体日期是非常方便的。就我而言,我不明白为什么我会在一周中的某一天运行计划脚本(仅当它是在 13 号时),以您的示例为例。

  • 13 号星期五只是为了说明。更常见的是希望编写诸如“0 0 1-7 * 6”之类的内容 - “该月的第一个星期六”(即 crontab 仅当满足两个条件时才会执行该命令)。但是,无论如何,是否存在一种情况(或者你能想象一种情况),你需要使用类似“在每月的第 N 天和每周的第 M 天运行相同的脚本”(这就是 crontab 现在的工作方式)? (8认同)
  • -1,有几个原因。首先,不清楚您所说的*“对于我们来说,能够在应该在一周中的某一天运行的脚本上指示特定日期是非常方便的。”*(事实上,这听起来与它完全相同) *不可能*做到这一点,并且您说您看不到下一句话的要点。其次,对于您*“看不到原因”*任何人的行为都有简单且常见的用例想要有 - 例如上面@AlexanderShmidt 描述的“该月的第一个星期六”场景。 (5认同)