我读到了一份在该月最后一天安排脚本的说明:
笔记:
精明的读者可能想知道如何设置在每个月的最后一天执行的命令,因为您无法设置涵盖每个月的 dayofmonth 值。这个问题一直困扰着 Linux 和 Unix 程序员,并催生了相当多不同的解决方案。常见的方法是添加一个 if-then 语句,使用 date 命令检查明天的日期是否为 01:00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command1
它会在每天中午 12 点检查是否是该月的最后一天,如果是,则 cron 运行该命令。
怎样[`date +%d -d tomorrow` = 01 ]
运作?
表述正确吗then; command1
?
答案1
抽象的
正确的代码应该是:
#!/bin/sh
[ "$#" -eq 0 ] && echo "Usage: $0 command [args]" && exit 1
[ "$(date -d tomorrow +'%d')" = 01 ] || exit 0
exec "$@"
调用这个脚本end_of_month.sh
,在 cron 中的调用很简单:
00 12 28-31 * * /path/to/script/end_of_month.sh command
这将仅在第 28、29、30 和 31 天运行脚本end_of_month
(内部将检查该天是否为该月的最后一天)。无需在任何其他日期检查月末。
旧帖子。
这是 Richard Blum、Christine Bresnahan 所著的《Linux Command Line and Shell Scripting Bible》一书的引文,第 442 页,第三版,John Wiley & Sons ©2015。
是的,这就是它所说的,但这是错误的/不完整的:
- 缺少结束语
fi
。 [
和 以下之间需要空格`
。- 这是强烈地建议使用 $(...) 而不是
`…`
. - 使用引号很重要扩展喜欢
"$(…)"
;
后面还有一个补充then
我怎么知道? (好吧,根据经验☺)但你可以尝试外壳检查。粘贴书中的代码(星号后面),它将显示上面列出的错误以及“missing shebang”。 Shellcheck 中没有任何错误的脚本是这样的:
#!/bin/sh if [ "$(date +%d -d tomorrow)" = 01 ] ; then script.sh; fi
该网站之所以有效,是因为编写的内容是“shell 代码”。这是一种适用于许多 shell 的语法。
shellcheck 没有提到的一些问题是:
假设 date 命令是 GNU date 版本。带有
-d
接受tomorrow
作为值的选项的选项(busybox 有一个 -d 选项,但不理解明天,BSD 有一个-d
选项,但与时间的“显示”无关)。最好设置一下格式后所有选项
date -d tomorrow +'%d'
。cron 启动时间始终采用当地时间,如果设置或未设置 DST(夏令时),这可能会使一项作业比确切的天数提前或晚 1 小时启动。
我们完成的是一个可以用 cron 调用的 shell 脚本。我们可以进一步修改脚本以接受要执行的程序或命令的参数,如下所示(最后是正确的代码):
#!/bin/sh
[ "$#" -eq 0 ] && echo "Usage: $0 command [args]" && exit 1
[ "$(date -d tomorrow +'%d')" = 01 ] || exit 0
exec "$@"
调用这个脚本end_of_month.sh
,在 cron 中的调用很简单:
00 12 28-31 * * /path/to/script/end_of_month.sh command
这将仅在第 28、29、30 和 31 天运行脚本end_of_month
(内部将检查该天是否为该月的最后一天)。无需在任何其他日期检查月末。
确保包含正确的路径。 cron 内的 PATH 不会(不太可能)与用户 PATH 相同。
请注意,有一月末脚本经测试(如下所示)可以调用许多其他实用程序或脚本。
这也将避免 cron 使用完整命令行生成的额外问题:
- Cron 会在任何一个命令行上分割命令行,
%
即使用'
or引用"
(这里只有 a\
有效)。这是 cron 作业失败的常见方式。
您可以end_of_month.sh
通过使用 faketime 测试脚本来测试脚本在某个日期是否正常工作(无需等到月底才发现它不起作用):
$ faketime 2018/10/31 ./end_of_month echo "Command will be executed...."
Command will be executed....
答案2
假设语法错误已修复,并且命令稍微重新编写以变得不那么冗长:
00 12 28-31 * * [ "$( date -d tomorrow +\%d )" != "01" ] || command1
运行该程序date +%d -d tomorrow
(假设date
使用的是 GNU)以获取两位数形式的明天日期。如果号码不是01
,那么今天不是该月的最后一天。在这种情况下,测试成功并且command1
是不是被执行。该作业在可能是该月最后一天的中午运行。
原来的命令:
00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command1
这有几个问题:
- 后面没有空格
[
。 - 直接
;
在then
. %
在 cron 作业规范中很特殊,必须转义为\%
(请参阅man 5 crontab
)。fi
最后没有与 相匹配的决赛if
。
答案3
要安排每个月的最后一天,您可以尝试:0 0 15,L * *
。
答案4
在你的 crontab 中
00 01 * * * [ $(date +\%d) -eq $(date \-d "-$(date +\%d) days month" +\%d) ] && /path/to/script.sh
以上将在该月最后一天凌晨 1 点运行。