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

我想通过在每天的特定时间每周二执行的cron来执行一个任务。 每个星期二都很简单:

0 6 * * Tue 

但是如何在“每个第二个星期二”(或者如果你更喜欢 – 每隔一周)做到这一点呢? 我不想在自己的脚本中实现任何逻辑,但只保留在cron的定义。

怎么样,即使它没有在前五个字段中完全定义,它仍然保留在crontab

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

回答

修改你的星期二cron逻辑, 从那个纪元开始每隔一周执行一次。

知道一周有604800秒(忽略DST变化和闰秒,谢谢),并使用GNUdate:

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

在旁边

日历算术令人沮丧。

@ xahtep的回答非常棒,但是,正如@Doppelganger在评论中指出的那样 ,它在某些年份会失败。 date实用程序的“每周”说明符都不能在这里帮助。 一月初的一些周二将不可避免地重复上周最后一个星期的平价:2016-01-05(%V),2018-01-02(%U)和2019-01-01(%W) 。

pilcrow的答案是伟大的。 然而,这会导致每周甚至每周运行一次fortnightly.sh脚本(从时代开始)。 如果你需要脚本运行几个星期,你可以稍微调整他的答案:

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

将1更改为0会将其移回到几周。

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

第一个cronjob:

 0 0 8 ? 1/1 TUE#1 * 

第二个cronjob:

 0 0 8 ? 1/1 TUE#3 * 

不知道这里的语法,我用http://www.cronmaker.com/来做这些。;

每第三周怎么样?

这是我的build议:

 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 

…取决于周旋转。

如果你只想每个星期二的第二周:

00 06 * * 2#2

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

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

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

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

假设GMT-2:

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

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

为了解决这个问题,我们需要根据我们的本地时区而不是UTC来计算UTC的偏移量。 我在BASH中找不到一个简单的方法,所以我开发了一个解决scheme,它使用Perl中的快速内存来计算从几秒钟内UTC的偏移量。

此脚本利用date+%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 

Cron提供“隔一个”语法“/ 2”。 只需按照适当的时间单位字段中的“/ 2”,它会每隔一段时间执行一次cronjob。 在你的情况下…

 0 6 * * Tue/2 

上面应该每隔一个星期二执行一次。

语法“/ 2”不是星期几。 所以我添加到上面的聪明只是使用MonthDay提交1,15。

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

为什么不喜欢

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

这是否合适?