Як я можу сказати cron виконувати команду через день (непарне / парне)


45

Під час налаштування cron виконувати команду через день, використовуючи поле "День місяця", наприклад:

1 22 */2 * * COMMAND

він працює щоразу, коли день місяця є непарним: 1,3,5,7,9 тощо.

Як я можу налаштувати cron на такі місячні дні, які навіть схожі на 2,6,8,10 тощо (не вказуючи це буквально, що проблематично, оскільки кожен місяць має різну кількість днів у місяці)?

Відповіді:


60

Синтаксис, який ви спробували, насправді неоднозначний. Залежно від того, скільки днів у місяці, в деяких місяцях воно буде працювати в непарні дні, а в деяких парні. Це тому, що спосіб його обчислення займає загальну кількість можливостей і ділить їх. Ви можете подолати цю страхітливу поведінку, вручну вказавши діапазон днів і використовуючи непарне або парне число днів. Оскільки сценарії навіть денного дня ніколи не працюватимуть на 31 день довших місяців, ви не втрачаєте нічого, використовуючи 30 днів як основу для парних днів, і, конкретно вказавши, щоб розділити його так, як якщо б було 31 день, ви можете примусити непарно -денне виконання.

Синтаксис виглядатиме так:

# Will only run on odd days:
0 0 1-31/2 * * command

# Will only run on even days:
0 0 2-30/2 * * command

Ваша турбота про те, що місяці не матимуть однакову кількість днів, тут не важливі, оскільки в місяцях немає БОЛЬШИХ днів, ніж цей, а для поганого лютого діапазон дат ніколи не відповідатиме останній день чи два, але це не принесе шкоди, коли вона перерахована.

Єдиний "gotcha" для цього підходу полягає в тому, що якщо ви перебуваєте на циклі непарних днів, наступні місяці з 31 днями ваша команда також буде працювати першого місяця. Так само, якщо ви змушуєте рівномірний цикл, кожен високосний рік спричинятиме один триденний цикл і кінець лютого. Ви дійсно не можете обійти той факт, що будь-який регулярний зразок "через день" не завжди випаде на парні або непарні дні кожного місяця, і будь-яким способом, який ви змусите це, у вас буде або зайвий пробіг, або пропущений пробіг між місяці з рахунком пропущених днів.


1
Дякую, але що відбудеться у такі місяці, як лютий, коли у вас всього 28 днів? Зірка насправді опікується цим - але насправді неоднозначно.
freddie

3
@freddie: Дивіться мою відредаговану відповідь ... але це не питання, оскільки значення поза діапазоном просто ігноруються, 30 або 31 лютого нічого не відбудеться. Колись. Ви можете вручну вказати такий список, як 0,2,4...,30,32,34це не має значення, значення поза діапазоном ніколи не збігаються.
Калеб

1
Дякую! Розумію, дякую за інформативну відповідь!
freddie

3
На сервері Ubuntu 8.04 здається, що синтаксис, що використовує нуль дня місяця, недійсний (поганий день місяця). Однак прийнято такий синтаксис:0 0 2-30/2 * * command

1
Fedora та RHEL 5,6,7 також не люблять 0 як день місяця. Як зазначав user31053: 0 0 2-30/2 * * commandпрацює як очікувалося.
NoelProf

2

Я думаю, що існує можливість використання дня року, такого як:

# for odd days
test $(((`date +%j` % 2))) != 0 && command

# for even days
test $(((`date +%j` % 2))) == 0 && command

Він тестується на системи Unix та Linux.


Я віддаю перевагу цій відповіді, тому що вона пропускає проблему з непарною кількістю днів з деякими місяцями. У будь-якому разі я пропоную замість долара нотацію:test $(($(date +%j) % 2)) == 0 && command
caligari

Я переглянув, що% j не є юліанською датою, тому найкращий код, який уникає переходу на Новий рік, повинен обчислюватися секундами:test $(($(date +%s) / 86400 % 2)) == 0 && command
caligari

Дякуємо за коментарі! Наша пропозиція спрацювала для нас як шарм. Ми використовували цю схему для щоденного запуску кронів на різних вузлах сервера, всі вони спільно використовували один і той же crontab, але сценарій дозволяє запускати сценарій лише на одному з них. Однак, якщо нам потрібно зробити це більш конкретним, ми розглянемо вашу пропозицію. Дякую!!!
Джорді,

1

Давайте щодня перевіряємо, чи це "інше" :-) ( bcпотрібна програма)

0 0 * * * test $(echo `date +%s` / 86400 % 2 == 0 |bc) -eq 0 && command

(Я не впевнений, що код відображається правильно. date +%sЧастина знаходиться між спинами-апострофами.)


Це працюватиме через день, але не дає відповіді на запитання! Він все одно буде працювати іноді в непарні дні, іноді в парні дні залежно від місяця. Це має той самий результат, що і код у запитанні, ви просто досягаєте результату, роблячи власну математику за секунди з епохи. Це триває по днях, починаючи з епохи, але не за рівними днями нашого календаря.
Калеб

1

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

Створити простий файл статусу, який повідомляє, коли останній запуск, а потім порівняння, буде працювати дуже легко.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.