如何指导cron每两周执行一次工作?

时间:2008-12-08 16:18:41

标签: linux unix cron scheduling

我想通过cron运行一份工作,该工作将在每天的特定时间每两周执行一次。每个星期二都很容易:

0 6 * * Tue

但是如何在“每隔一个星期二”(或者如果你愿意 - 每隔一周)进行一次? 我不想在它自己的脚本中实现任何逻辑,但只保留在cron中的定义。

14 个答案:

答案 0 :(得分:41)

答案

将星期二的cron逻辑修改为自纪元以来每隔一周执行

知道一周有604800秒(忽略DST更改和闰秒,谢谢),并使用GNU日期:

0 6 * * Tue expr `date +\%s` / 604800 \% 2 >/dev/null || /scripts/fortnightly.sh

除了

日历算法很令人沮丧。

@ xahtep的回答非常好,但是,如@Doppelganger noted in comments,它将在某些年份的边界上失败。 date实用程序的“一年中的一周”说明符都不能在这里提供帮助。 1月初的某个星期二将不可避免地重复前一年最后一个星期二的周平价:2016-01-05(%V),2018-01-02(%U)和2019-01-01(%W)

答案 1 :(得分:40)

这个怎么样,它确实将它保留在crontab中,即使它在前五个字段中没有完全定义:

0 6 * * Tue expr `date +\%W` \% 2 > /dev/null || /scripts/fortnightly.sh

答案 2 :(得分:7)

pilcrow's answer很棒。但是,它导致fortnightly.sh脚本每隔甚至周运行一次(自纪元以来)。如果您需要脚本在奇数周运行,您可以稍微调整一下他的答案:

0 6 * * Tue expr \( `date +\%s` / 604800 + 1 \) \% 2 > /dev/null || /scripts/fortnightly.sh

将1更改为0会将其移回甚至数周。

答案 3 :(得分:2)

也许有点愚蠢,但也可以创造两个cronjobs,每个第一个星期二一个,每三个一个。

第一个cronjob:

0 0 8 ? 1/1 TUE#1 *

第二个cronjob:

0 0 8 ? 1/1 TUE#3 *

我不确定这里的语法,我使用http://www.cronmaker.com/来制作这些语法。

答案 4 :(得分:1)

我发现上述方法的一些额外限制可能会在某些边缘情况下失败。例如,考虑:

  

@xahtep和@Doppelganger在上述某些年度边界上使用%W讨论了问题。

     

@ pilcrow的答案在某种程度上解决了这个问题,但它也会在某些边界上失败。此和/或其他相关主题中的答案使用一天中的秒数(相对于一周),出于同样的原因,这些秒数在某些边界上也会失败。

这是因为这些方法依赖于UTC时间(日期+%s)。考虑一下我们在每个第二个星期二凌晨1点和10点开始工作的情况。

假设GMT-2:

  • 当地时间凌晨1点= UTC时间晚上11点昨天
  • 当地时间晚上10点=晚上8点UTC 今天

如果我们每天只检查一次,这不会是一个问题,但如果我们多次检查 - 或者如果我们接近UTC时间并且夏令时发生,则脚本不会认为这些是同一天。

为了解决这个问题,我们需要根据我们的本地时区而不是UTC计算UTC的偏移量。我无法在BASH中找到一种简单的方法,所以我开发了一种解决方案,它使用Perl中的快速单行程序来计算UTC的偏移量。

此脚本利用日期+%z,输出本地时区。

Bash脚本:

TZ_OFFSET=$( date +%z | perl -ne '$_ =~ /([+-])(\d{2})(\d{2})/; print eval($1."60**2") * ($2 + $3/60);' )
DAY_PARITY=$(( ( `date +%s` + ${TZ_OFFSET} ) / 86400 % 2 ))

然后,确定这一天是偶数还是奇数:

if [ ${DAY_PARITY} -eq 1 ]; then
...
else
...
fi

答案 5 :(得分:1)

如果要根据给定的开始日期进行操作:

0 6 * * 1 expr \( `date +\%s` / 86400 - `date --date='2018-03-19' +\%s` / 86400 \) \% 14 == 0 > /dev/null && /scripts/fortnightly.sh

应该从2018-03-19开始每隔一个星期一触发一次

表达式为:如果...,星期一星期一上午6点运行。

1-获取今天的日期(以秒为单位)除以一天中的秒数,以转换为天数(秒)

2-对开始日期执行相同的操作,将其转换为自纪元以来的天数

3-获取两者之间的差异

4-除以14,然后检查余数

5-如果余数为零,则您处于两周的周期中

答案 6 :(得分:1)

类似的东西

0 0 1-7,15-21 * 2

本月的第一个和第三个星期二。

注意:不要将它与 vixie cron(包含在 RedHat 和 SLES 发行版中)一起使用,因为它在月份和星期几字段之间使用 or 而不是 and。

答案 7 :(得分:0)

每隔3周一次呢?

这是我的建议:

0 6 * * Tue expr `date +\%W` \% 3 == 0 > /dev/null || /scripts/fortnightly.sh

......或......

0 6 * * Tue expr `date +\%W` \% 3 == 1 > /dev/null || /scripts/fortnightly.sh

...当然......

0 6 * * Tue expr `date +\%W` \% 3 == 2 > /dev/null || /scripts/fortnightly.sh

......取决于周轮换。

答案 8 :(得分:0)

0 0 * / 14 * *

每个月的第14天在00:00投放

答案 9 :(得分:0)

试试这个

0 0 1-7,15-21 * 2

每月运行 2 次,每周二和至少相隔一周。

答案 10 :(得分:-1)

如果你想要每周二的第二周:

00 06 * * 2#2

答案 11 :(得分:-2)

语法“/ 2”与工作日不一致。所以我添加到上面的智能只是在MonthDay上使用1,15。

0 6 1,15 * * /scripts/fornightly.sh> / dev / null 2>& 1

答案 12 :(得分:-2)

为什么不喜欢

0 0 1-7,15-21,29-31 * 5

这合适吗?

答案 13 :(得分:-3)

Cron提供“每隔一个”语法“/ 2”。只需使用“/ 2”跟随相应的时间单位字段,它将“每隔一段时间”执行一次cronjob。在你的情况下......

0 6 * * Tue/2

上述情况应该每隔一个星期二执行一次。