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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/350047/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 16:47:28  来源:igfitidea点击:

How to instruct cron to execute a job every second week?

linuxunixcronscheduling

提问by tkokoszka

I would like to run a job through cron that will be executed every second Tuesday at given time of day. For every Tuesday is easy:

我想通过 cron 运行一项工作,该工作将在每天的第二个星期二在给定时间执行。每个星期二很容易:

0 6 * * Tue

But how to make it on "every second Tuesday" (or if you prefer - every second week)? I would not like to implement any logic in the script it self, but keep the definition only in cron.

但是如何在“每个第二个星期二”(或者如果您愿意 - 每两周一次)做到这一点?我不想在自己的脚本中实现任何逻辑,而是只在 cron 中保留定义。

采纳答案by xahtep

How about this, it does keep it in the crontabeven if it isn't exactly defined in the first five fields:

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

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

回答by macetw

What about every 3rd week?

每第三周呢?

Here's my suggestion:

这是我的建议:

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

... or ...

... 或者 ...

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

... or of course ...

……或者当然……

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

... depending on the week rotation.

...取决于周轮换。

回答by jimmyb

Cron provides an 'every other' syntax "/2". Just follow the appropriate time unit field with "/2" and it will execute the cronjob 'every other time'. In your case...

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

0 6 * * Tue/2

The above should execute every other Tuesday.

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

回答by Izi

Syntax "/2" is not goes along with weekday. So my added to the smart above is simply use 1,15 on MonthDay filed.

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

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

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

回答by Hans

Maybe a little dumb, but one could also create two cronjobs, one for every first tuesday and one for every third.

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

First cronjob:

第一个定时任务:

0 0 8 ? 1/1 TUE#1 *

Second cronjob:

第二个定时任务:

0 0 8 ? 1/1 TUE#3 *

Not sure about the syntax here, I used http://www.cronmaker.com/to make these.

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

回答by pilcrow

Answer

回答

Modify your Tuesday cron logic to execute every other week since the epoch.

修改您的星期二 cron 逻辑,使其自 epoch 以来每隔一周执行一次。

Knowing that there are 604800 seconds in a week (ignoring DST changes and leap seconds, thank you), and using GNU date:

知道一周有604800秒(忽略夏令时变化和闰秒,谢谢),使用GNU日期:

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

Aside

在旁边

Calendar arithmetic is frustrating.

日历算术令人沮丧。

@xahtep's answer is terrific but, as @Doppelganger noted in comments, it will fail on certain year boundaries. None of the dateutility's "week of year" specifiers can help here. Some Tuesday in early January will inevitably repeat the week parity of the final Tuesday in the preceding year: 2016-01-05 (%V), 2018-01-02 (%U), and 2019-01-01 (%W).

@xahtep 的回答很棒,但正如@Doppelganger 在评论中指出的那样,它会在某些年份边界上失败。该date实用程序的“一年中的一周”说明符都无济于事。1 月初的某个星期二不可避免地会重复上一年最后一个星期二的周平价:2016-01-05 (%V)、2018-01-02 (%U) 和 2019-01-01 (%W) .

回答by isaac

Why not something like

为什么不像

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

Is that appropriate?

那合适吗?

回答by notorious.dds

pilcrow's answeris great. However, it results in the fortnightly.sh script running every evenweek (since the epoch). If you need the script to run on oddweeks, you can tweak his answer a little:

pilcrow 的回答很棒。然而,这导致每运行fortnightly.sh脚本甚至一周(自纪元)。如果您需要脚本在奇数周运行,您可以稍微调整他的答案:

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

Changing the 1 to a 0 will move it back to even weeks.

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

回答by alexdourado

If you want every tuesday of second week only:

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

00 06 * * 2#2

00 06 * * 2#2

回答by dxdc

I discovered some additional limitations of above approaches that can fail in some edge cases. For instance, consider:

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

@xahtep and @Doppelganger discussed issues using %Won certain year boundaries above.

@pilcrow's answer gets around this to some degree, however it too will fail on certain boundaries. Answers in this and or other related topics use the number of seconds in a day (vs. week), which also fail on certain boundaries for the same reasons.

@xahtep 和 @Doppelganger 讨论了%W在上述特定年份边界上使用的问题。

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

This is because these approaches rely on UTC time (date +%s). Consider a case where we're running a job at 1am and 10pm every 2nd Tuesday.

这是因为这些方法依赖于 UTC 时间(日期 +%s)。考虑这样一个案例,我们在每个第二个星期二的凌晨 1 点和晚上 10 点运行一项工作。

Suppose GMT-2:

假设 GMT-2:

  • 1am local time = 11pm UTC yesterday
  • 10pm local time = 8pm UTC today
  • 当地时间凌晨 1 点 = UTC昨天晚上 11 点
  • 当地时间晚上 10 点 = UTC今天晚上 8 点

If we are only checking a single time each day, this will not be an issue, but if we are checking multiple times -- or if we are close to UTC time and daylight savings occurs, the script wouldn't consider these to be the same day.

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

To get around this, we need to calculate an offset from UTC based on our localtimezone not UTC. I couldn't find a simple way to do this in BASH, so I developed a solution that uses a quick one liner in Perl to compute the offset from UTC in seconds.

为了解决这个问题,我们需要根据我们的本地时区而不是 UTC来计算与 UTC 的偏移量。我找不到在 BASH 中执行此操作的简单方法,因此我开发了一种解决方案,该解决方案使用 Perl 中的快速单行代码以秒为单位计算与 UTC 的偏移量。

This script takes advantage of date +%z, which outputs the local timezone.

此脚本利用 date +%z,它输出本地时区。

Bash script:

bash脚本:

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

then, to determine whether the day is even or odd:

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

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