【问题标题】:Why crontab uses OR when both day of month and day of week specified?为什么 crontab 在指定月份和星期几时使用 OR?
【发布时间】:2016-03-25 06:02:30
【问题描述】:

这是一个著名的“问题”,即当 crontab 行同时包含星期几和月份中的某天时,cron 使用 OR 来确定触发命令的日期。 例如。如果你写

* * 13 * 5 command

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

所以我的问题是:这个例外是否有特定的原因?我的意思是,应该有一个原因,但我似乎找不到它。 (相反,我在互联网上看到很多人希望将这些领域与其他领域一样对待 - 使用“AND 策略”,正是针对“13 日星期五”或“5 月第 2 个星期四”之类的内容。)

【问题讨论】:

    标签: linux unix cron crontab


    【解决方案1】:

    我在 Unix 服务器上工作,该服务器在 crontab 中使用了许多脚本。对于我们来说,能够在应该在一周中的某一天运行的脚本上指示特定日期是非常方便的。就我而言,我不明白为什么我会在一周中的某一天运行预定的脚本,如果它是在 13 号,以你为例。

    【讨论】:

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

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

    具体来说,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.
     */
    

    因此,听上去,即使是您可能正在使用的 Cron 的实施者,也不会比我给出的非解释更深入地了解您的问题的答案这个答案的第一段。

    【讨论】:

      【解决方案3】:

      从 Vixie cron 再往前走一步,“wday OR mday”逻辑出现在 System V cron 中,但 System III 或更早版本中没有。

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

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

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

      要尝试了解 SysV 中发生了什么,查看源代码(before - SysIII 和 after - SVr4)以及新行为的文档会有所帮助:

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

      (摘自 SunOS 4.1.3 手册页。在这方面似乎是 SysV-ish。在 Paul Vixie 编写他的替代品之前,BSD cron 从未有过这种行为。)

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

      可以通过两个字段(月中的日和周中的日)来指定日期。如果指定为元素列表,则两者都被遵守。

      SysV 代码完全重写。它的一个特点是,当没有作业即将运行时,它会休眠很长时间。 (旧的 cron 每分钟唤醒一次,并将当前时间与所有作业规范进行比较。)计算函数顶部的注释 (next_time) 解释:NOTE: this routine is hard to understand.

      确实很难理解。它是“查找此 crontab 行的下一个执行时间”功能,而不是“确定当前时间是否与该 crontab 行匹配”功能,因此甚至需要花费一些精力才能弄清楚该函数中隐含的匹配规则,当mday 和 wday 都不是*,是(month AND hour AND minute AND (mday OR wday))。

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

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

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

      【讨论】:

        猜你喜欢
        • 2019-06-02
        • 2021-12-16
        • 2017-04-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-14
        • 2013-09-25
        • 1970-01-01
        相关资源
        最近更新 更多