我想在每个月初开始一项工作,但只在工作日。
为此,我在 /etc/crontab 文件中添加了此行:
7 0 3-5 * 1-5 root ( test "`date '+\%d'`" = "03" || test "`date '+\%u'`" = "1" ) && /path/to/my/script.sh
预期结果:script.sh 在每月 3 号到 5 号之间的第一个工作日启动(“测试”部分只是为了确保它启动一次)。
它运行得很好,本月 3 号,cronjob 就运行了。
但不幸的是,出于未知原因,它也在今天(6 月 8 日,星期一)启动了。我可以理解“测试”部分有效(test "date '+%u'" = "1"
是真的,而且合乎逻辑),但“cron”部分不应该是真的(7 0 3-5 * 1-5
不是真的,我们是 8 号)。
所以我想知道,我做错了什么吗,或者是否存在更深层次的问题?
谢谢!
答案1
这种确实令人惊讶的行为记录在man 5 crontab
(重点是我的):
当分钟、小时和月份字段与当前时间匹配时,cron(8) 会执行命令,什么时候最后一个两个日期字段(月份中的日期或星期几)与当前时间匹配(见下文“注释”)。
[...]
注意:命令执行的日期可以通过两个字段指定 - 月份日期和星期几。如果两个字段都受到限制(即不是 *),
当任一字段与当前时间匹配时,命令将运行例如,“30 4 1,15 * 5”将导致命令在每个月 1 日和 15 日以及每个星期五的凌晨 4:30 运行。
因此,您需要做的是让您的命令测试时间。就像您让它只运行一次一样。由于这变得有点复杂,我建议在您的脚本本身中完成检查,然后在相关月份的每一天启动 cron 命令。类似
## Check if this is a weekday
[ $(date '+%u') -le 5 ] && [ $(date '+%u') -ge 1 ] || exit;
## Make sure it only runs once. If yesterday was also a weekday and
## date >=3 and <=5, we can assume the script ran then and should exit.
[ $(date -d yesterday '+%u') -le 5 ] && [ $(date -d yesterday '+%u') -ge 1 ] &&
[ $(date -d yesterday '+%d') -le 3 ] && [ $(date -d yesterday '+%d') -ge 5 ] && exit;
## Rest of your script goes here
[...]
然后,从 开始cron
,仅在每个月的第 3 至 5 天启动您的脚本:
7 0 3-5 * * /path/to/my/script.sh