每三天进行一次 Cron 作业

Posted

技术标签:

【中文标题】每三天进行一次 Cron 作业【英文标题】:Cron job every three days 【发布时间】:2011-05-31 18:37:52 【问题描述】:

是否可以每三天运行一次cronjob?或者每月 10 次。

【问题讨论】:

是的,这是可能的,这属于超级用户。 无论月份界限如何,每 3 天运行一次,可以使用 anacron 完成。 【参考方案1】:

每三天运行一次...

0 0 */3 * *

怎么样?

如果您希望它在每月的特定日期运行,例如 1 日、4 日、7 日等...那么您可以在脚本中添加一个条件来检查当月的当前日期。

if (((date('j') - 1) % 3))
   exit();

或者,正如@mario 指出的那样,您可以使用 date('k') 来获取一年中的哪一天,而不是根据月份中的哪一天来获取。

【讨论】:

@whatshakin:这取决于您希望“每三天”的准确度。这适用于可以被 3 整除的任何一天。在月份边界上它不会是精确的。 @whatshakin: cronjob 语法甚至在 Wikipedia 上有描述:en.wikipedia.org/wiki/Cronjob 这在 google 上是一个非常高的结果,因此如果接受的答案是正确的会更好,但事实并非如此。我相信Tareco的解释是正确的。 答案不正确,因为这两个建议实际上都不是每 3 天运行一次作业。 0 0 */3 * * 表示在 1 日、4 日、7 日等运行(*/3 表示 1-31/3 表示 1,4,7...31),因此月底差距会更小。 (如果上个月有 31 天,它将连续运行 2 天。)date('j') % 3 有一个类似的问题,该模式每年都会重新启动,并且年份没有可被 3 整除的天数。 我也很遗憾,这被接受为答案。我真的在寻找每 N 天,不管月份的界限(植物之类的东西不关心他们在一个月的哪一天得到水)。至少我认为我在阅读所有 cmets 后确定,cron 计时器本身并不能完全模拟这种愿望。【参考方案2】:
* * */3 * *  that says, every minute of every hour on every three days. 

0 0 */3 * *  says at 00:00 (midnight) every three days.

【讨论】:

欣赏解释 这通常每三天触发一次,但可以在月初的第二天触发【参考方案3】:

因为 cron 是“无状态的”,它不能准确地表达“频率”,只能表达它(显然)与当前时间连续匹配的“模式”。

改写您的问题会使这一点更加明显:“是否可以在每晚 00:01 运行 cronjob,除了在 2 晚内运行的跳过之夜?”当 cron 将当前时间与作业请求时间模式进行比较时,cron 无法知道它是否在过去运行过您的作业。

(当然可以编写一个有状态的 cron 来记录过去的作业,因此包括用于匹配该状态的模式,但这不是大多数操作系统中包含的标准 cron。这样的系统会因为需要引入这种模式何时“重置”的概念。例如,当时间更改时模式是否会重置(即 crontab 条目被修改)?看看你最喜欢的日历应用程序,看看它可以有多复杂来表达计划的重复模式事件,并注意它们没有重置问题,因为开始日历事件有一个自然的“开始”a/k/a“重置”日期。尝试重新安排每隔一周的循环日历事件以推迟一周, 例如在圣诞节。通常你必须终止该重复事件并重新启动一个全新的事件;这说明了即使是复杂的日历应用程序如何表示重复模式的表达能力有限。当然还有日历 h有很多状态——每个单独的事件都可以被删除或独立重新安排[在大多数日历应用程序中])。

此外,您可能希望每 3 晚完成一次工作如果成功,但如果最后一次失败,请立即重试,可能在第二天晚上(不要再等 3 天)甚至更快,比如一个小时后(但在早上到来时停止重试)。显然,cron 不可能知道您的工作是否成功,并且该模式也无法表达替代的更频繁的“重试”计划。

无论如何-- 你可以自己做你想做的事。编写一个脚本,告诉 cron 每晚在上午 00:01 运行它。该脚本可以检查记录“上次运行”的某事*的时间戳,如果是 >3 天前**,则执行该作业并重置“上次运行”时间戳。

(*那个带时间戳的指标是一种持久化状态,您可以对其进行操作和检查,但 cron 不能)

**如果您使用人类可读的时钟时间,请注意时间算术 - 一年两次,有些日子一天有 23 或 25 小时,而 02:00-02:59 在一天内出现两次或者根本没有。使用 UTC 来避免这种情况。

【讨论】:

【参考方案4】:

我不是 cron 专家,但如何:

0 */72 * * *

它将每 72 小时不间断运行。

https://crontab.guru/#0_/72___

【讨论】:

这比公认的解决方案更准确。更改月份时接受的答案将失败:then at 2019-02-28 00:00:00 then at 2019-03-01 00:00:00 根据crontab.guru 每天运行。谁是对的? 根据crontab.guru和man crontab,小时列中的值必须在0到23之间。 */72 实际上与 0 相同。它在每个午夜运行。 我对此进行了测试。它每天都在运行。【参考方案5】:

我不认为你有你需要的东西:

0 0 */3 * * ## <<< WARNING!!! CAUSES UNEVEN INTERVALS AT END OF MONTH!!

不幸的是,*/3 将间隔设置为每月的每一天不是每 n 天。请参阅:explanation here。在月底,保证会定期出现问题。

1st  at 2019-02-01 00:00:00
then at 2019-02-04 00:00:00 << 3 days, etc. OK
then at 2019-02-07 00:00:00
...
then at 2019-02-25 00:00:00
then at 2019-02-28 00:00:00
then at 2019-03-01 00:00:00 << 1 day WRONG
then at 2019-03-04 00:00:00
...

根据this article,您需要在正在执行的命令中添加一些模数学以获得“每 N 天”的 TRUE。例如:

0 0 * * *  bash -c '(( $(date +\%s) / 86400 \% 3 == 0 )) && runmyjob.sh'

在此示例中,作业将在每天上午 12:00 进行检查,但仅在自 01-01-1970 以 3 为模的天数为 0 时才会执行。

如果您希望从特定日期开始每 3 天发送一次,请使用以下格式:

0 0 * * *  bash -c '(( $(date +\%s -d "2019-01-01") / 86400 \% 3 == 0 )) && runmyjob.sh'

【讨论】:

【参考方案6】:
0 0 1-30/3 * *

这将从 1 日开始每三天运行一次。这是 20 次预定运行 -

2015-06-01 00:00:00 2015-06-04 00:00:00 2015-06-07 00:00:00 2015-06-10 00:00:00 2015-06-13 00:00:00 2015-06-16 00:00:00 2015-06-19 00:00:00 2015-06-22 00:00:00 2015-06-25 00:00:00 2015-06-28 00:00:00 2015-07-01 00:00:00 2015-07-04 00:00:00 2015-07-07 00:00:00 2015-07-10 00:00:00 2015-07-13 00:00:00 2015-07-16 00:00:00 2015-07-19 00:00:00 2015-07-22 00:00:00 2015-07-25 00:00:00 2015-07-28 00:00:00

【讨论】:

2015-07-31 00:00:00, 2015-08-01 00:00:00... OOPS 运行之间只有 1 天【参考方案7】:

怎么样:

00 00  *  *   * every 3 days && echo test

every 是一个脚本:

#!/bin/sh

case $2 in
    days)
        expr `date +%j` % $1 = 0 > /dev/null
        ;;

    weeks)
        expr `date +%V` % $1 = 0 > /dev/null
        ;;

    months)
        expr `date +%m` % $1 = 0 > /dev/null
        ;;
esac

所以它每天都在运行。

使用*/3 在每月的 3 号、6 号、... 27 号、30 号运行,但在一个月有第 31 天之后就出错了。 every 脚本只有在年底之后才会出错。

【讨论】:

【参考方案8】:

如果您将其配置为仅运行例如,它会更简单。在星期一和星期四,这将给它提供 3 和 4 天的休息时间。

否则将其配置为每天运行,但让您的 php cron 脚本提前退出:

if (! (date("z") % 3)) 
     exit;

【讨论】:

【参考方案9】:

由于 UTC 天数正好是 86400 秒(所有天数,忘记闰秒,它们不会影响 UTC 天数),将(整数除法)纪元时间(以秒为单位)除以 86400 得到(完整)经过的天数自纪元。通过更多的数学运算,我们可能会到达这条 cron 行:

12 21 * * * [ $(( ($(date +\%s)/86400+0) \% 3 )) = 0 ]  && do_stuff

如果今天是08/30/2021New_York,则执行命令的最佳时间是21:12(或更晚),以确保天。在这样的时间和日期,命令将被执行。如果需要移动当天,则将0更改为适当的偏移量,以获得当天的0-day

也可以使用任何其他循环n(而不是 3)。

结果不受月、年或世纪的影响。总会有n天的周期

请注意,cron 要求将 % 转义为 \%

【讨论】:

【参考方案10】:

如果您希望它在一个月的特定日期运行,例如 1 号、4 号、7 号等...那么您可以在脚本中添加一个条件来检查当月的当前日期。

我认为您需要的只是代替 */3 表示每三天一次,使用 1/3 表示从本月 1 日开始每三天一次。所以 7/3 表示从每月 7 日开始每三天一次,以此类推。

【讨论】:

【参考方案11】:

0 0 * * * [ $(($((date +%-j- 1)) % 3)) == 0 ] &amp;&amp; script

date获取一年中的哪一天,从0开始偏移1,检查是否为模三。

【讨论】:

当它从非闰年滚动到下一年时,不会打嗝吗,因为( 365-1 ) % 3 == 1( 1 - 1 ) % 3 == 0?我认为更好的计算将基于自 Unix 纪元以来的天数。【参考方案12】:

你应该学习crontab的基础知识。

通过命令crontab -e 编辑 cron,然后 ⌃ (CTRL) + X 然后 Y 最后按 ENTER ( return) 在 mac 上保存文件。您可以通过crontab -l检查新的crons是否已安装

一个 crontab 文件有五个字段用于指定分钟、小时、日期 月份、月份和星期几,然后是命令 以该间隔运行。

*     *     *   *    *   command to be executed
-     -     -   -    -
|     |     |   |    |
|     |     |   |    +----- day of week (0-6) (Sunday=0)
|     |     |   +------- month (1-12)
|     |     +--------- day of month (1-31)
|     +----------- hour (0-23)
+------------- min (0-59)

上面值字段中的* 表示该列的大括号中的所有合法值。

在这里,我写了一篇关于它的详细帖子:Setup Cron in Unix

【讨论】:

这如何回答 OP? 这并没有真正回答问题。

以上是关于每三天进行一次 Cron 作业的主要内容,如果未能解决你的问题,请参考以下文章

每 30 秒运行一次 cron 作业的最佳方式是啥? [复制]

使用 Node-Cron 每 45 分钟运行一次 Cron 作业

Cron 作业——每 5 秒运行一次

使用 Node-Cron 每 10 秒执行一次 Cron 作业

每天 2:30 运行一次 cron 作业?

每 5 分钟运行一次 Cron 作业,持续 10 秒