从 1 月 16 日开始每 10 天设置一个 cron

Set a cron every 10 days starting from 16th January

如何设置一个 cron 以从 16th January 开始每隔 10 days 执行一次?这够了吗?

30 7 16-15/10 * * command >/dev/null

以上内容从 7.30 AM16th of every month 开始,到 next month 15th 结束,每隔 10 days 重复一次。我认为我上面的内容不正确。任何人都可以告诉我如何设置 cron 以便考虑到月末并且每个 10 days 命令从 16th January this year 2016 开始执行吗?

0 30 7 1/10 * ? * command >/dev/null

以上表达的输出是,

Saturday, January 16, 2016 7:30 AM 
    1.  Thursday, January 21, 2016 7:30 AM
    2.  Sunday, January 31, 2016 7:30 AM
    3.  Monday, February 1, 2016 7:30 AM
    4.  Thursday, February 11, 2016 7:30 AM
    5.  Sunday, February 21, 2016 7:30 AM

表达式的输出

i.e 30 7 16-15/10 * * command >/dev/null

    2016-01-15 07:30:00
    2016-02-15 07:30:00
    2016-03-15 07:30:00
    2016-04-15 07:30:00
    2016-05-15 07:30:00
    2016-06-15 07:30:00
    2016-07-15 07:30:00
    2016-08-15 07:30:00
    2016-09-15 07:30:00
    2016-10-15 07:30:00

最接近的语法如下:

30 7 1-30/10 * *
30 7 1-31/10 * *
30 7 1-28/10 * *
30 7 1-29/10 * *

您可以在此处测试 cron 表达式 http://cron.schlitt.info/

正如 William 所建议的,cron 本身无法处理这种复杂性。但是,您可以 运行 更频繁地执行 cron 作业,并为逻辑使用其他东西。例如;

30 7 16-31 1 * date '+\%j' | grep -q '0$' && yourcommand
30 7 *  2-12 * date '+\%j' | grep -q '0$' && yourcommand

此日期格式字符串打印一年中的第几天,从 001 到 365。grep -q 将进行模式匹配,不打印结果,但 return 成功或失败它发现的基础。每隔 10 天,一年中的某一天就会以零结束。在那些日子里,yourcommand 得到 运行。

roll-over 年份有问题。一个更复杂的替代方案可能是对 date '+%s'(纪元秒)的乘积执行类似的 grep,但您需要进行数学运算将秒数转换为天数以供 grep 分析。这可能有效(你应该测试):

SHELL=/bin/bash

30 7 * * * echo $(( $(date '+%s') / 86400 )) | grep '0$' && yourcommand

(当然也加上你的 1 月 16 日逻辑。)

这依赖于 shell 算术只能处理整数这一事实。 shell 只是 t运行 分类而不是四舍五入。


更新

在对另一个答案的评论中,您阐明了您的要求:

The command should start executing on January 16th, and continue like on January 26th, February 5th, February 15th and so on – jai

为此,epoch-second 方法可能是正确的方向。

% date -v1m -v16d -v7H -v30M -v0S '+%s'
1452947400

(我在 FreeBSD 中,因此这些论点 date。)

SHELL=/bin/bash

30 7 * * * [[ $(( ($(date '+\%s') - 1452947400) \% 864000 )) == 0 ]] && yourcommand

此表达式从当前时间减去 7:30AM 1 月 16 日(我的时区)的纪元秒,并测试所得差异是否可以被 10 天整除。如果是,则表达式的计算结果为真,您的命令为 运行。请注意,对于 $x.

的任何值,$(( 0 % $x )) 的计算结果为 0

如果 cron 特别忙并且无法在数学计算出来的那一秒内完成您的工作,这可能容易出错。

如果你想让它变得更复杂(甚至可能是 this 复杂),我建议你将逻辑移动到一个单独的 shell 脚本中以处理日期比较数学。特别是如果您计划添加一个软糖因素以允许作业错过其 1 秒 window .. 这可能是多行脚本,这在单个 cronjob 条目中维护起来很尴尬。

观察:cron 的数学能力仅次于non-existent。 Unix 工具的数学功能是无穷无尽的。

结论:将问题从cron域移至shell域。

解决方案:运行每天在 crontab 中使用 30 7 * * * /path/to/script

#!/bin/sh
PATH=$(/usr/bin/getconf PATH)
if test $(($(date +%j) % 10)) = 6; then
    your_command
fi

这测试 day-of-year 模 10 是否为 6,就像 1 月 16 日一样(而 1 月 6 日已经过去了......)。

跳出框框思考: 解决您的要求。说服想出那个有趣的 10 天周期的人接受 7 天周期。 cron 就容易多了。这是遵循 KISS 原则。