在月的最后一天运行的 CRON 作业

我需要创建一个 CRON 作业,将运行在每个月的最后一天。 我将使用 cPanel 创建它。

感谢你的帮助。 谢谢

232089 次浏览

您可以设置一个 cron 作业,在一个月的每一天运行,并让它运行一个 shell 脚本,如下所示。这个脚本计算出明天的天数是否比今天的少(也就是说,如果明天是一个新的月份) ,然后做任何你想做的事情。

TODAY=`date +%d`
TOMORROW=`date +%d -d "1 day"`


# See if tomorrow's day is less than today's
if [ $TOMORROW -lt $TODAY ]; then
echo "This is the last day of the month"
# Do stuff...
fi
00 23 * * * [[ $(date +'%d') -eq $(cal | awk '!/^$/{ print $NF }' | tail -1) ]] && job

在 unix.com 论坛上查看 相关问题

可能最简单的方法就是做三份不同的工作:

55 23 30 4,6,9,11        * myjob.sh
55 23 31 1,3,5,7,8,10,12 * myjob.sh
55 23 28 2               * myjob.sh

不过,即使在闰年,这种情况也会发生在2月28日上,因此,如果这是一个问题,你需要找到另一种解决办法。


然而,在每个月的 第一日尽快运行工作通常更容易也更正确,比如:

0 0 1 * * myjob.sh

并修改脚本来处理 上一页月份的数据。

这样可以消除您在确定哪一天是该月的最后一天时可能遇到的任何麻烦,并且还可以确保该月的所有数据都是可用的,假设您正在处理数据。在这个月的最后一天,在距离午夜还有五分钟的时候跑步,你可能会错过任何在午夜到午夜之间发生的事情。

无论如何,对于大多数月底的工作来说,这是通常的做法。


如果您仍然希望在每月的最后一天运行 真的,一种选择是简单地检测明天是否是第一天(或者作为脚本的一部分,或者在 crontab 本身中)。

比如:

55 23 28-31 * * [[ "$(date --date=tomorrow +\%d)" == "01" ]] && myjob.sh

应该是一个良好的开端,假设您有一个相对智能的 date程序。

如果你的 date程序不够先进,不能给你相对的日期,你可以把一个非常简单的程序放在一起,给你明天的一个月的一天(你不需要 date满了功率) ,例如:

#include <stdio.h>
#include <time.h>


int main (void) {
// Get today, somewhere around midday (no DST issues).


time_t noonish = time (0);
struct tm *localtm = localtime (&noonish);
localtm->tm_hour = 12;


// Add one day (86,400 seconds).


noonish = mktime (localtm) + 86400;
localtm = localtime (&noonish);


// Output just day of month.


printf ("%d\n", localtm->tm_mday);


return 0;
}

然后使用(假设你把它称为 tomdom,意思是“每月的第二天”) :

55 23 28-31 * * [[ "$(tomdom)" == "1" ]] && myjob.sh

不过您可能需要考虑添加错误检查,因为如果出现错误,time()mktime()都可以返回 -1。为了简单起见,上面的代码没有考虑到这一点。

设置一个 cron 作业在每月的第一天运行。那就把系统的时钟改成提前一天。

您只需将所有答案连接到一个 cron 行,并只使用 date命令即可。

检查一下今天和明天的月份之间的差别:

0 23 * * * root [ $(expr $(date +\%d -d '1 days') - $(date +\%d)  ) -le 0 ]  && echo true

如果这些差异小于0,这意味着我们改变了月份,并且有一个月的最后一天。

有一个稍微短一点的方法可以用来类似于上面的方法,那就是:

[ $(date -d +1day +%d) -eq 1 ] && echo "last day of month"

此外,crontab 条目可以更新到只检查在28日至31日,因为它是毫无意义的运行它的其他天的一个月。也就是说:

0 23 28-31 * * [ $(date -d +1day +%d) -eq 1 ] && myscript.sh

对于基于@Indie 解决方案的 crontab 中更安全的方法(使用 date + $()的绝对路径不适用于所有 crontab 系统) :

0 23 28-31 * * [ `/bin/date -d +1day +\%d` -eq 1 ] && myscript.sh

这个怎么样,在维基百科之后?

55 23 L * * /full/path/to/command

根据 paxDiablo 的解决方案,我在第28个2月29日上跑步。29号的数据覆盖了28号。

# min  hr  date     month          dow
55   23  31     1,3,5,7,8,10,12   * /path/monthly_copy_data.sh
55   23  30     4,6,9,11          * /path/monthly_copy_data.sh
55   23  28,29  2                 * /path/monthly_copy_data.sh

一些 cron 实现支持“ L”标志来表示月的最后一天。

如果你幸运地使用了其中的一个实现,它就像这样简单:

0 55 23 L * ?

每月最后一天晚上11:55开始。

Http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger

这个怎么样?

编辑用户的 .bashprofile添加:

export LAST_DAY_OF_MONTH=$(cal | awk '!/^$/{ print $NF }' | tail -1)

然后将这个条目添加到 crontab:

mm hh * * 1-7 [[ $(date +'%d') -eq $LAST_DAY_OF_MONTH ]] && /absolutepath/myscript.sh
#########################################################
# Memory Aid
# environment    HOME=$HOME SHELL=$SHELL LOGNAME=$LOGNAME PATH=$PATH
#########################################################
#
# string         meaning
# ------         -------
# @reboot        Run once, at startup.
# @yearly        Run once a year, "0 0 1 1 *".
# @annually      (same as @yearly)
# @monthly       Run once a month, "0 0 1 * *".
# @weekly        Run once a week, "0 0 * * 0".
# @daily         Run once a day, "0 0 * * *".
# @midnight      (same as @daily)
# @hourly        Run once an hour, "0 * * * *".
#mm     hh      Mday    Mon     Dow     CMD # minute, hour, month-day month DayofW CMD
#........................................Minute of the hour
#|      .................................Hour in the day (0..23)
#|      |       .........................Day of month, 1..31 (mon,tue,wed)
#|      |       |       .................Month (1.12) Jan, Feb.. Dec
#|      |       |       |        ........day of the week 0-6  7==0
#|      |       |       |        |      |command to be executed
#V      V       V       V        V      V
*       *       28-31   *       *       [ `date -d +'1 day' +\%d` -eq 1 ] && echo "Tomorrow is the first today now is  `date`" >> ~/message
1       0       1       *       *       rm -f ~/message
*       *       28-31   *       *       [ `date -d +'1 day' +\%d` -eq 1 ] && echo "HOME=$HOME LOGNAME=$LOGNAME SHELL = $SHELL PATH=$PATH"

对于 AWS Cloudwatch cron 实现(调度 Lambdas 等) ,这样可以:

55 23 L * ? *

每月最后一天晚上11:55开始。

55 23 28-31 * * echo "[ $(date -d +1day +%d) -eq 1 ] && my.sh" | /bin/bash

每个月的最后一天可以是28-31,这取决于它是哪个月(二月,三月等)。然而,在这两种情况下,第二天总是下个月的第一天。因此,我们可以使用下面的代码来确保我们总是在一个月的最后一天运行一些作业:

0 8 28-31 * * [ "$(date +%d -d tomorrow)" = "01" ] && /your/script.sh

不知道其他语言,但 在 javascript 中是可能的。

如果你需要你的 工作须在每月第一天前完成节点-cron 将允许你设置时区-你必须设置 UTC + 12:00,如果工作不是太长的世界大部分将有结果之前开始的一个月。

如果“每月的日期”字段可以接受“零日”字段,那么这个问题就可以很简单地解决了。天文学家用零日来表示上个月的最后一天。那么

00 08 00 * * /usr/local/sbin/backup

会用简单易行的方法做这项工作。

在第一天的下个月安排 cron 的更好方法

这将在上午12:00运行 foo 命令。

001 * */usr/bin/foo

我找到了解决方案(在月的最后一天)如下从 这个网站

 0 0 0 L * ? *

CRON 详情:

Seconds Minutes Hours   Day Of Month    Month   Day Of Week  Year
0       0       0       L               *       ?            *

为了交叉验证上面的表达式,点击这里给出如下输出。

2021-12-31 Fri 00:00:00
2022-01-31 Mon 00:00:00
2022-02-28 Mon 00:00:00
2022-03-31 Thu 00:00:00
2022-04-30 Sat 00:00:00

如果在午夜至凌晨1点之间运行,那么在“日期”程序中要小心使用“昨天”、“今天”、“一天”,因为这些通常意味着“24小时”,也就是夏时制改变导致一天23小时运行的两天。我用“ date-d’1 am-12 hour”

在像 Jenkins 这样的工具中,通常不支持 L,也不支持类似于 date的工具,一个很酷的技巧可能是正确设置时区。例如,太平洋/基里蒂马蒂是格林尼治标准时间 + 14:00,所以如果你在欧洲或美国,这可能会奏效。

TZ=Pacific/Kiritimati \n H 0 1 * *

结果: 最后一次跑步时间是2022年4月30日星期六,格林尼治时间上午10:54:53; 下一次跑步时间是2022年5月31日星期二,格林尼治时间上午10:54:53。

使用下面的代码在每月的最后一天在 PHP 中运行 cron

$commands = '30 23 '.date('t').' '.date('n').' *';