Мені потрібно створити роботу CRON, яка працюватиме в останній день кожного місяця. Я буду створювати його за допомогою cPanel.
Будь-яка допомога вдячна. Дякую
Мені потрібно створити роботу CRON, яка працюватиме в останній день кожного місяця. Я буду створювати його за допомогою cPanel.
Будь-яка допомога вдячна. Дякую
Відповіді:
Можливо, найпростіший спосіб - це просто зробити три окремі роботи:
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
та модифікуйте сценарій для обробки даних попереднього місяця.
Це усуває будь-які клопоти, з якими ви можете зіткнутися з з’ясуванням того, який день є останнім у місяці, а також гарантує доступність усіх даних за цей місяць, за умови, що ви обробляєте дані. Запуск від п’яти хвилин до півночі останнього дня місяця може призвести до того, що ви пропустите все, що трапиться з того часу до півночі.
Це звичайний спосіб зробити це в будь-якому випадку для більшості робочих місць наприкінці місяця.
Якщо ви все ще дійсно хочете , щоб запустити його в останній день місяця, один з варіантів є просто виявити , якщо завтра буде перший (або як частина вашого сценарію, або в самому кронтаб).
Отже, щось на кшталт:
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
якщо що - то піде не так. У наведеному вище коді з міркувань простоти це не враховано.
Існує дещо коротший метод, який можна використовувати, подібний до одного з наведених вище. Це є:
[ $(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
/bin/sh: -c: line 1: unexpected EOF while looking for matching ')'
.
[ $(date -d +1day +\%d) -eq 1 ] && run_job
posix
і дата POSIX не підтримує "-d +1day"
: - \ Більш складним (і негарним) рішенням було б:[ `date +\%d` -eq `cal | xargs echo | awk '{print $NF}'` ] && myscript.sh
Налаштуйте завдання cron для запуску в перший день місяця. Потім змініть годинник системи на один день попереду.
Адаптуючи рішення 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
,29
.
55 23 28 2
?
Ви можете встановити завдання 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
Деякі реалізації cron підтримують прапор "L", який представляє останній день місяця.
Якщо вам пощастить використовувати одну з цих реалізацій, це так просто, як:
0 55 23 L * ?
Це триватиме о 23:55 останнього дня кожного місяця.
http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger
#########################################################
# 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 (планування лямбда тощо) це працює:
55 23 L * ? *
Працює о 23:55 останнього дня кожного місяця.
00 23 * * * [[ $(date +'%d') -eq $(cal | awk '!/^$/{ print $NF }' | tail -1) ]] && job
Перевірте відповідне питання на форумі unix.com.
Ви можете просто з'єднати всі відповіді в один рядок cron і використовувати лише date
команду.
Просто перевірте різницю між днем місяця, який сьогодні є і буде завтра:
0 23 * * * root [ $(expr $(date +\%d -d '1 days') - $(date +\%d) ) -le 0 ] && echo true
Якщо ця різниця нижче 0, це означає, що ми міняємо місяць і є останній день місяця.
55 23 28-31 * * echo "[ $(date -d +1day +%d) -eq 1 ] && my.sh" | /bin/bash
Як що до цього?
редагувати .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
Останній день місяця може бути 28-31 залежно від того, який це місяць (лютий, березень тощо). Однак у будь-якому з цих випадків наступний день завжди є 1 числа наступного місяця. Отже, ми можемо використовувати це, щоб переконатися, що ми виконуємо якусь роботу завжди в останній день місяця, використовуючи код нижче:
0 8 28-31 * * [ "$(date +%d -d tomorrow)" = "01" ] && /your/script.sh