安排每个月的最后一天

Abs*_*cDo 10 cron shell-script date test

我从指令中阅读了在本月最后一天安排脚本的说明:

注意:
精明的读者可能想知道如何设置命令在每个月的最后一天执行,因为您无法将 dayofmonth 值设置为涵盖每个月。这个问题一直困扰着 Linux 和 Unix 程序员,并产生了很多不同的解决方案。一种常用的方法是添加一个 if-then 语句,该语句使用 date 命令来检查明天的日期是否为 01:

00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command1
Run Code Online (Sandbox Code Playgroud)

这会在每天中午 12 点检查是否是该月的最后一天,如果是,则 cron 运行该命令。

在此处输入图片说明

如何[`date +%d -d tomorrow` = 01 ]工作?
陈述正确then; command1吗?

ImH*_*ere 17

抽象的

正确的代码应该是:

#!/bin/sh
[ "$#" -eq 0 ] && echo "Usage: $0 command [args]" && exit 1
[ "$(date -d tomorrow +'%d')" = 01 ] || exit 0
exec "$@"
Run Code Online (Sandbox Code Playgroud)

调用这个脚本end_of_month.sh,cron 中的调用很简单:

00 12 28-31 * * /path/to/script/end_of_month.sh command
Run Code Online (Sandbox Code Playgroud)

这将end_of_month仅在第 28、29、30 和 31 天运行脚本(内部将检查该天是否为当月的最后一天)。无需在任何其他日期检查月末。

旧帖。

这是 Richard Blum 所著的“Linux Command Line and Shell Scripting Bible”一书中的引述,Christine Bresnahan pp 442,第三版,John Wiley & Sons ©2015。

是的,这就是它所说的,但这是错误的/不完整的:

  • 缺少结束语fi
  • [和以下之间需要空格`
  • 这是强烈建议使用$(...)代替`…`
  • 重要的是在扩展周围使用引号,例如"$(…)"
  • ;后面还有一个then

我怎么知道?(好吧,根据经验?)但您可以尝试Shellcheck。粘贴书中的代码(在星号之后),它会显示上面列出的错误以及“丢失的shebang”。Shellcheck 中没有任何错误的脚本是这样的:

#!/bin/sh if [ "$(date +%d -d tomorrow)" = 01 ] ; then script.sh; fi

该站点有效,因为编写的是“shell 代码”。这是一种适用于许多 shell 的语法。

shellcheck 没有提到的一些问题是:

  • 假设 date 命令是 GNU 日期版本。带有一个-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 "$@"
Run Code Online (Sandbox Code Playgroud)

调用这个脚本end_of_month.sh,cron 中的调用很简单:

00 12 28-31 * * /path/to/script/end_of_month.sh command
Run Code Online (Sandbox Code Playgroud)

这将end_of_month仅在第 28、29、30 和 31 天运行脚本(内部将检查该天是否为当月的最后一天)。无需在任何其他日期检查月末。

确保包含正确的路径。cron 中的 PATH 不会(不太可能)与用户 PATH 相同。

请注意,有一个已测试的月末脚本(如下所示)可以调用许多其他实用程序或脚本。

这也将避免 cron 使用完整命令行生成的额外问题:

  • %即使用'或引用"\此处仅适用),Cron也会在任何命令行上拆分命令行。这是 cron 作业失败的常见方式。

您可以end_of_month.sh通过使用 faketime 进行测试来测试脚本在某个日期是否正常工作(无需等到月底才发现它不起作用):

$ faketime 2018/10/31 ./end_of_month echo "Command will be executed...."
Command will be executed....
Run Code Online (Sandbox Code Playgroud)

  • 经验已经(多次)证明,用 faketime 测试正确运行的脚本比等到月底发现预定的作业没有工作要好得多。就像发现 `* * * * * echo "$(date -u +'date %c')" >>~/testfile` 因为忘记引用 `\%`(如果只是每个月都可以尝试一次)。@库萨兰南达 (2认同)

Kus*_*nda 9

假设语法错误是固定的,并且命令稍微重新编写以减少冗长:

00 12 28-31 * * [ "$( date -d tomorrow +\%d )" != "01" ] || command1
Run Code Online (Sandbox Code Playgroud)

这运行date +%d -d tomorrow(假设使用的是 GNU date)以获取明天的日期作为两位数。如果数字不是01,则今天不是该月的最后一天。在这种情况下,试验成功,command1不会执行。作业在可能是本月最后一天的中午运行。

原始命令:

00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command1
Run Code Online (Sandbox Code Playgroud)

这有几个问题:

  • 后没有空格[
  • A;直接之后then
  • %在 cron 作业规范中是特殊的,必须将其转义为\%(参见man 5 crontab)。
  • 最后没有fiif.

  • @cat无论你如何引用`"`或`'`(```\```除外),百分号`%`将使cron将行分成两部分。这是一种常见的让 cron 失败的方法。 (3认同)
  • 使用 `[ ... ] && command1` 而不是 `if...` 的问题在于,在不是该月最后一天的日子里,cron 作业将以非零退出状态结束,并且 *可能需要报告失败*。使用 `[ "$(...)" != 01 ] || command1` 是另一种避免该问题的方法。 (2认同)