Я прочитал инструкцию, чтобы запланировать сценарий на последний день месяца:
Примечание
. Проницательному читателю может быть интересно, как вы можете настроить команду для выполнения в последний день каждого месяца, потому что вы не можете установить значение 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
?
источник
; endif
?[
и безfi
в конце. Кроме того,%
является особенным в crontabs.Ответы:
абстрактный
Правильный код должен быть:
Вызовите этот скрипт,
end_of_month.sh
и вызов в cron просто:Это запустит сценарий
end_of_month
(который внутренне проверит, что день является последним днем месяца) только в дни 28, 29, 30 и 31. Нет необходимости проверять конец месяца в любой другой день.Старый пост.
Это цитата из книги Ричарда Блюма «Командная строка Linux и библейские сценарии», Кристина Бреснахан, стр. 442, третье издание, John Wiley & Sons © 2015.
Да, это то, что говорится, но это неправильно / неполно:
fi
.[
и следующим`
.`…`
."$(…)"
;
послеthen
Откуда мне знать? (ну, по опыту ☺) но вы можете попробовать Shellcheck . Вставьте код из книги (после звездочек), и он покажет вам ошибки, перечисленные выше, плюс «недостающий шебанг». Сценарий без каких-либо ошибок в Shellcheck это:
#!/bin/sh if [ "$(date +%d -d tomorrow)" = 01 ] ; then script.sh; fi
Этот сайт работает, потому что написано "код оболочки". Это синтаксис, который работает во многих оболочках.
Некоторые проблемы, которые не затрагивает shellcheck:
Предполагается, что команда date является версией даты GNU. Тот, у которого есть
-d
опция, которая принимаетtomorrow
в качестве значения (busybox имеет опцию -d, но не понимает завтра, а BSD имеет-d
опцию, но не связана с «отображением» времени).Лучше установить формат после всех опций
date -d tomorrow +'%d'
.Время запуска cron всегда указывается по местному времени, что может означать, что одно задание запускается на 1 час раньше, чем точный счетчик дней, если установлено летнее время (DST) или не установлено.
То, что мы сделали, - это скрипт оболочки, который можно вызвать с помощью cron. Мы можем дополнительно изменить скрипт, чтобы он принимал аргументы программы или команды для выполнения, например так (наконец, правильный код):
Вызовите этот скрипт,
end_of_month.sh
и вызов в cron просто:Это запустит сценарий
end_of_month
(который внутренне проверит, что день является последним днем месяца) только в дни 28, 29, 30 и 31. Нет необходимости проверять конец месяца в любой другой день.Убедитесь, что указан правильный путь. PATH внутри cron не будет (маловероятно) таким же, как пользовательский PATH.
Обратите внимание, что есть один протестированный скрипт на конец месяца (как указано ниже), который может вызывать многие другие утилиты или скрипты.
Это также позволит избежать дополнительной проблемы, которую cron генерирует с полной командной строкой:
%
даже если она заключена в кавычки или'
или"
(только здесь\
работает). Это распространенный способ провалов заданий cron.Вы можете проверить,
end_of_month.sh
правильно ли работает скрипт на какой-либо дате (не дожидаясь конца месяца, чтобы обнаружить, что он не работает), протестировав его с помощью faketime:источник
date
(илиdate
встроенная в ksh93, если ksh93 была построена как часть ast-open) поддерживаетdate -d tomorrow +%s
илиdate +%s tomorrow
).* * * * * echo "$(date -u +'date %c')" >>~/testfile
сработает, потому что забыли процитировать\%
(что становится трудно отлаживать, если возможна только одна попытка в месяц). @ КусаланандаПредполагая, что синтаксические ошибки исправлены, и команда немного переформулирована, чтобы быть менее многословной:
Это выполняется
date +%d -d tomorrow
(при условии, что используется GNUdate
), чтобы получить завтрашнюю дату в виде двузначного числа. Если число не01
, то сегодня не последний день месяца. В этом случае испытания успешно , иcommand1
это не выполняется. Работа выполняется в полдень в дни, которые могут быть последним днем месяца.Оригинальная команда:
Это имеет несколько проблем:
[
.;
сразу послеthen
.%
является особенным в спецификациях работы cron и должен быть экранирован как\%
(см.man 5 crontab
).fi
конце нет финала , совпадающего сif
.источник
[ ... ] && command1
вместо этогоif...
состоит в том, что в дни, не являющиеся последним днем месяца, задание cron заканчивается с ненулевым состоянием выхода, и о сбое может потребоваться сообщить. Использование[ "$(...)" != 01 ] || command1
это еще один способ избежать проблемы.;
междуthen
иcommand1
."
или'
(кроме\
), знак процента%
заставит cron разбить строку на две части. Это один из обычных способов заставить cron потерпеть неудачу.Для того, чтобы запланировать в последний день каждого месяца, вы можете попробовать:
0 0 15,L * *
.источник