Задание Cron для запуска в последний день месяца - PullRequest
79 голосов
/ 26 мая 2011

Мне нужно создать задание cron, которое будет запускаться каждый последний день месяца. Я создам его из cpanel.

Любая помощь приветствуется. Спасибо

Ответы [ 14 ]

151 голосов
/ 26 мая 2011

Возможно, самый простой способ - просто выполнить три отдельных задания:

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

Это произойдет 28 февраля, хотя, даже в високосные годы, поэтому, если это проблема, вам нужно найти другой путь.


Однако обычно значительно проще и правильнее запускать задание как можно скорее в первый день каждого месяца, например,

0 0 1 * * myjob.sh

и измените скрипт для обработки данных предыдущего месяца.

Это устраняет любые трудности, с которыми вы можете столкнуться при выяснении того, какой день является последним в месяце, а также обеспечивает доступность всех данных за этот месяц, при условии, что вы обрабатываете данные. Запуск в пять минут до полуночи в последний день месяца может привести к тому, что вы пропустили все, что происходит между тем и до полуночи.

Это обычный способ сделать это для большинства работ на конец месяца.


Если вы все еще действительно хотите запустить его в последний день месяца, один из вариантов - просто определить, наступит ли завтра первое (либо как часть вашего скрипта, либо в самом crontab) .

Итак, что-то вроде:

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

должно быть хорошим началом, если у вас достаточно умная date программа.

Если ваша date программа не достаточно продвинута, чтобы дать вам относительные даты, вы можете просто собрать очень простую программу, чтобы дать вам завтрашний день месяца (вам не нужно full мощность 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, если что-то пойдет не так. Приведенный выше код по соображениям простоты не учитывает это.

46 голосов
/ 26 августа 2011

Есть немного более короткий метод, который можно использовать аналогично одному из приведенных выше. То есть:

[ $(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
17 голосов
/ 26 мая 2011

Настройка задания cron для запуска в первый день месяца. Затем измените часы системы на один день вперед.

10 голосов
/ 17 мая 2013

Адаптируя решение paxdiablo, я бегу 28 и 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
10 голосов
/ 15 марта 2012

А как насчет этого после Википедии?

55 23 L * * /full/path/to/command
6 голосов
/ 26 мая 2011

Вы можете настроить задачу cron для запуска каждый день месяца и запустить скрипт оболочки, как показано ниже.Этот сценарий определяет, меньше ли номер завтрашнего дня, чем сегодняшний (т. Е. Если завтра новый месяц), а затем выполняет все, что вы хотите.

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
5 голосов
/ 05 сентября 2013

Некоторые реализации cron поддерживают флаг "L" для представления последнего дня месяца.

Если вам повезло использовать одну из этих реализаций, это так же просто, как:

0 55 23 L * ?

Это будет выполняться в 23:55 в последний день каждого месяца.

http://www.quartz -scheduler.org / documents / quartz-1.x/ учебники / CronTrigger

5 голосов
/ 06 марта 2012

Для более безопасного метода в crontab на основе решения @Indie (использование абсолютного пути к date + $() работает не во всех системах crontab):

0 23 28-31 * * [ `/bin/date -d +1day +\%d` -eq 1 ] && myscript.sh
4 голосов
/ 29 марта 2018

Для реализации cron в AWS Cloudwatch (планирование Lambdas и т. Д.) Это работает:

55 23 L * ? *

Работает в 23:55 в последний день каждого месяца.

4 голосов
/ 28 февраля 2015
#########################################################
# 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" 
...