Чому мій crontab не працює, і як його усунути?


225

Це канонічне запитання щодо використання cron & crontab.

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

Відповідь на тему: " Чому мій crontab не працює, і як його усунути?" 'можна побачити нижче. Це адресація cronсистеми з виділеним кронтабом.


2
Це величезна дура Причини, чому crontab не працює на AskUbuntu.
Дан Даскалеску

1
@DanDascalescu Здається, що Еріку потрібно отримати більше представників
я

1
Я щойно приєднався до сервера Fault SE (тому всього 101 повтор), але хотів би дати це питання -1 !! Це питання було зроблене лише для того, щоб отримати представник? @IamtheMostStupidPerson Цілком з вами згоден ...
Holyprogrammer

Західна ідеологія у цих 13-річних падаванців є і підручником, і сліпучою, як суперна. Щоб відповісти на обидва ваші запитання: так, я зробив це для представника, і так, Еріку потрібно отримати більше репутації. Скільки ще мені потрібних представників ?? Більше. youtu.be/IaDt9T7BF38?t=262
Ерік Лещинський

Відповіді:


317

Як виправити всі ваші проблеми / проблеми, пов’язані з Crontab (Linux)


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


По-перше, основна термінологія:

  • cron (8) - демон, який виконує заплановані команди.
  • crontab (1) - програма, яка використовується для зміни файлів користувача crontab (5).
  • crontab (5) - це файл на кожного користувача, який містить інструкції для cron (8).

Далі, освіта про cron:

У кожного користувача системи може бути власний файл crontab. Розташування кореневих та користувацьких файлів crontab залежать від системи, але вони, як правило, нижче /var/spool/cron.

Існує загальносистемний /etc/crontabфайл, /etc/cron.dкаталог може містити фрагменти crontab, які також читаються та діють cron. У деяких дистрибутивах Linux (наприклад, Red Hat) також /etc/cron.{hourly,daily,weekly,monthly}є каталоги, сценарії всередині яких виконуватимуться щогодини / день / тиждень / місяць, з привілеєм root.

root завжди може використовувати команду crontab; постійні користувачі можуть або не можуть отримати доступ. Коли ви редагуєте файл crontab за допомогою команди crontab -eта зберігаєте його, crond перевіряє його на основну дійсність, але не гарантує, що ваш файл crontab правильно сформований. Існує файл, cron.denyякий називається, який визначає, які користувачі не можуть використовувати cron. Розташування cron.denyфайлу залежить від системи і його можна видалити, що дозволить усім користувачам використовувати cron.

Якщо комп'ютер не ввімкнено або демон не працює, а дата / час для запуску команди минув, crond не заповнюватиметься та не запускатиме минулі запити.

Деталі crontab, як сформулювати команду:

Команда crontab представлена ​​одним рядком. Ви не можете використовувати \команду для розширення команди на кілька рядків. Знак хеш ( #) представляє коментар, який означає, що що-небудь у цій лінії ігнорується cron. Провідні пробіли та порожні рядки ігноруються.

Будьте ДУЖЕ обережними, використовуючи %знак відсотка ( ) у вашій команді. Якщо вони не врятуються, \%вони перетворюються в нові рядки, і все після першого не втеченого %передається вашій команді на stdin.

Для файлів crontab є два формати:

  • Кронтабелі користувачів

    # Example of job definition:
    # .---------------- minute (0 - 59)
    # |  .------------- hour (0 - 23)
    # |  |  .---------- day of month (1 - 31)
    # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
    # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7)
    # |  |  |  |  |
    # *  *  *  *  *   command to be executed
    
  • Система широка /etc/crontabта /etc/cron.dфрагменти

    # Example of job definition:
    # .---------------- minute (0 - 59)
    # |  .------------- hour (0 - 23)
    # |  |  .---------- day of month (1 - 31)
    # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
    # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7)
    # |  |  |  |  |
    # *  *  *  *  * user-name  command to be executed
    

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

Перші 5 полів рядка представляють час (и), коли команду слід виконати. Ви можете використовувати номери або, де це можливо, імена днів / місяців у специфікації часу.

  • Поля розділені пробілами або вкладками.
  • Кома ( ,) використовується для вказівки списку, наприклад, 1,4,6,8, що означає запуск у 1,4,6,8.
  • Діапазони задаються тире ( -) і можуть поєднуватися зі списками, наприклад, 1-3,9-12, що означає від 1 до 3, а потім між 9 і 12.
  • /Символ може бути використаний для введення кроку , наприклад , 2/5 , що означає , починаючи з 2 , то кожні 5 (2,7,12,17,22 ...). Вони не загортаються повз кінця.
  • Зірочка ( *) у полі позначає весь діапазон для цього поля (наприклад, 0-59для хвилинного поля).
  • Діапазони та кроки можна комбінувати, наприклад, */2означає, починаючи з мінімального для відповідного поля, а потім кожні 2, наприклад, 0 хвилин (0,2 ... 58), 1 місяця (1,3 ... 11) тощо.

Налагодження команд cron

Перевірте пошту!

За замовчуванням cron надішле будь-який вихід з команди користувачеві, в якому виконується команда. Якщо виходу немає, пошти не буде. Якщо ви хочете, щоб cron надсилав пошту в інший рахунок, тоді ви можете встановити змінну середовища MAILTO у файлі crontab, наприклад

MAILTO=user@somehost.tld
1 2 * * * /path/to/your/command

Зробіть висновок самостійно

Ви можете перенаправити stdout та stderr у файл. Точний синтаксис для отримання виходу може відрізнятися залежно від того, який оболонку використовується cron. Ось два приклади, які зберігають весь вихід у файл за адресою /tmp/mycommand.log:

1 2 * * * /path/to/your/command &>/tmp/mycommand.log
1 2 * * * /path/to/your/command >/tmp/mycommand.log 2>&1

Подивіться на колоди

Cron реєструє свої дії через syslog, який (залежно від налаштувань) часто переходить на /var/log/cronабо /var/log/syslog.

Якщо потрібно, ви можете відфільтрувати заяви cron за допомогою напр

grep CRON /var/log/syslog 

Тепер, коли ми переглянули основи cron, де знаходяться файли та як їх використовувати, розглянемо деякі поширені проблеми.

Перевірте, чи працює cron

Якщо cron не працює, то ваші команди не будуть заплановані ...

ps -ef | grep cron | grep -v grep

повинен отримати вам щось подібне

root    1224   1  0 Nov16 ?    00:00:03 cron

або

root    2018   1  0 Nov14 ?    00:00:06 crond

Якщо не перезавантажте його

/sbin/service cron start

або

/sbin/service crond start

Можуть бути й інші методи; використовувати те, що надає ваш дистрибутив.

cron виконує вашу команду в обмеженому середовищі.

Те, що змінні середовища доступні, ймовірно, буде дуже обмеженим. Як правило, ви отримаєте тільки кілька змінних , визначених, наприклад $LOGNAME, $HOMEі $PATH.

Особливо слід зазначити, що PATHце обмежено /bin:/usr/bin. Переважна більшість проблем "мій сценарій не працює" викликані цим обмежувальним шляхом . Якщо ваша команда знаходиться в іншому місці, ви можете вирішити це двома способами:

  1. Надайте повний шлях до вашої команди.

    1 2 * * * /path/to/your/command
    
  2. Укажіть відповідний PATH у файлі crontab

    PATH=/usr:/usr/bin:/path/to/something/else
    1 2 * * * command 
    

Якщо вашій команді потрібні інші змінні середовища, їх можна визначити і у файлі crontab.

cron запускає вашу команду cwd == $ HOME

Незалежно від того, де програма, яку ви виконуєте, знаходиться у файловій системі, поточний робочий каталог програми, коли запускається cron, буде домашнім каталогом користувача . Якщо ви отримуєте доступ до файлів у вашій програмі, вам потрібно буде це врахувати, якщо ви використовуєте відносні шляхи або (бажано) просто використовувати повнокваліфіковані контури скрізь, і врятуйте всіх безліч плутанини.

Остання команда в моєму Crontab не працює

Cron, як правило, вимагає, щоб команди закінчувались новим рядком. Відредагуйте свій crontab; перейдіть до кінця рядка, який містить останню команду, і вставте новий рядок (натисніть Enter).

Перевірте формат crontab

Ви не можете використовувати користувацький crontab, відформатований crontab для / etc / crontab або фрагменти в /etc/cron.d і навпаки. Crontab, відформатований користувачем, не включає ім'я користувача у 6-му положенні рядка, тоді як системний формат crontab включає ім'я користувача та виконує команду як цей користувач.

Я поміщаю файл у /etc/cron.{hourly,daily,weekly,monthly}, і він не працює

  • Перевірте, чи немає у файлі розширення, див. Прогони
  • Переконайтеся, що файл має дозволи на виконання.
  • Скажіть системі, що використовувати під час виконання сценарію (наприклад, поставити #!/bin/shвгорі)

Помилки, пов’язані з датою Cron

Якщо ваша дата нещодавно змінилася користувачем або системою, оновленням часу, часовим поясом чи іншим, то crontab почне поводитися нестабільно і виявлятиме химерні помилки, іноді працює, іноді ні. Це спроба crontab спробувати "робити те, що ти хочеш", коли час змінюється з-під нього. Поле "хвилини" стане неефективним після зміни години. У цьому сценарії приймаються лише зірочки. Перезапустіть cron і повторіть спробу, не підключаючись до Інтернету (тому дата не має шансу повернутися на один із серверів часу).

Знову знаки відсотків

Щоб підкреслити поради щодо знаків відсотків, ось приклад того, що cron робить з ними:

# cron entry
* * * * * cat >$HOME/cron.out%foo%bar%baz

створить файл ~ / cron.out, що містить 3 рядки

foo
bar
baz

Це особливо нав'язливо при використанні dateкоманди. Обов’язково уникайте знаків відсотків

* * * * * /path/to/command --day "$(date "+\%Y\%m\%d")"

Можливо, хочете також відзначити у розділі «обмежене середовище», що LD_LIBRARY_PATH також може знадобитися встановити будь-які додаткові каталоги у випадку, якщо ваше завдання cron не виконане через неможливість пошуку спільних бібліотек.
DavidJ

зауважте, що ви навіть можете написати щось подібне: 35 1,5-23 / 2 * * * do_something замість 35,1,5,7,9, .. * * * Додатково цей crontab.guru перекладає записи, які ви робите людська мова.
Денніс Нолте

1
Захоплення виходу для мене не працює, можливо, через шкаралупу sh. Я думаю , що це більш портативне: ... /path/to/your/command >/tmp/mycommand.log 2>&1
Chus

це працювало для мене:sudo apt-get install postfix
jmunsch

чи робота cron також залежить від того, наскільки важкий файл? Оскільки я керував простим привітним світом у пітоні з кроном, він спрацював. Але мій другий код був трохи важким і, як правило, запускається, але з cron він не дає жодного виводу у файл.
Девендра Бхат

22

Debian Linux та його похідні (Ubuntu, Mint тощо) мають деякі особливості, які можуть перешкоджати виконанню ваших задач cron; зокрема, файли в /etc/cron.d, /etc/cron.{hourly,daily,weekly,monthly}повинні:

  • володіти коренем
  • бути доступним для запису під корінь
  • не можна писати для групи або інших користувачів
  • мати ім’я без крапки "." або будь-який інший спеціальний символ, окрім '-' та '_'.

Останній шкодить регулярно не підозрюючим користувачам; зокрема , будь-який скрипт , в одній з цих папок з ім'ям whatever.sh, mycron.py, testfile.plі т.д. , будуть НЕ виконуватися, коли - небудь.

На мій досвід, саме ця точка була, безумовно, найчастішою причиною невиконання спільної роботи на Debian та деривативах.

Детальніше man cronпро це див.


19

Якщо ваші кронштейни перестають працювати, перевірте, чи не минув термін дії вашого пароля. З моменту його закінчення всі роботи в cron припиняються.
З’являться повідомлення, /var/log/messagesподібні до наведеного нижче, де відображаються проблеми з автентифікацією користувача:

(username) FAILED to authorize user with PAM (Authentication token is no longer valid; new one required)


2
Щойно я отримав це також (файл повідомлення про помилку / var / log / syslog для мене). У моєму випадку поле DigitalOcean, яке під час створення часу скидає кореневий пароль (необов’язково) на інший, і, мабуть, до тих пір, поки ви не зайдете туди і не зміните його, усі завдання cron не виконуються. Бампер. Виправити щось на кшталтsudo -u root passwd
rogerdpack

12

Нечасті та нерегулярні розклади

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

Розглянемо наступне завдання, яке, як правило, пояснюється як "бігати commandкожні 5 хвилин" :

*/5 * * * * /path/to/your/command

проти:

*/7 * * * * /path/to/your/command

яка не завжди працює commandкожні 7 хвилин .

Пам’ятайте, що /персонаж може бути використаний для введення кроку, але що кроки не закінчуються після закінчення серії, наприклад, */7що відповідає кожні 7-й хвилини від хвилини, 0-59 тобто 0,7,14,21,28,35,42,49, 56 , але між одну годину і наступний буде тільки 4 хвилини між партіями , після того, як 00:56нова серія починається 01:00, і 01:07т.д. (і партії не буде працювати на 01:03, 01:10, і 01:17т.д.).


Що робити замість цього?

Створіть кілька партій

Замість того, щоб виконати одну задачу, створіть кілька партій, які об'єднають результат у бажаному графіку.

Наприклад, щоб запускати партію кожні 40 хвилин (00:00, 00:40, 01:20, 02:00 тощо), створіть дві партії: одна, яка працює двічі за парні години, і друга, яка працює лише в непарні години:

# The following lines create a batch that runs every 40 minutes i.e.

# runs on   0:00, 0:40,        02:00, 02:40         04:00 etc to 22:40
0,40 */2 * * * /path/to/your/command

# runs on               01:20,               03:20,       etc to 23:20
20 1/2 * * * /path/to/your/command

# Combined: 0:00, 0:40, 01:20, 02:00, 02:40, 03:20, 04:00 etc.

Бігайте партіями рідше

Замість того, щоб запускати свою партію кожні 7 хвилин, що складно розкладати на декілька партій, просто запускайте її кожні 10 хвилин.

Почніть запускати партії частіше (але не дозволяйте одночасно працювати кількома партіями)

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

Натомість подумайте інакше і створіть кронштейн, який витончено завершиться, коли попередній запуск ще не закінчився, але який буде працювати інакше. Дивіться це запитання :

* * * * * /usr/bin/flock -n /tmp/fcj.lockfile /usr/local/bin/frequent_cron_job 

Це майже одразу почне новий запуск після завершення попереднього запуску / usr / local / bin / часта_cron_job.

Почніть свої партії частіше (але виходьте витончено, коли умови не потрібні)

Оскільки синтаксис cron обмежений, ви можете вирішити розмістити більш складні умови та логіку в самому пакетному завданні (або в обгортковому скрипті навколо існуючого пакетного завдання). Це дозволяє використовувати розширені можливості улюблених мов сценарію, коментувати свій код і запобігатиме важко читаються конструкції в самому записі crontab.

seven-minute-jobТоді в bash виглядає щось на зразок:

#!/bin/bash
# seven-minute-job
# This batch will only run when 420 seconds (7 min) have passed
# since the file /tmp/lastrun was either created or updated

if [ ! -f /tmp/lastrun ] ; then
    touch /tmp/lastrun
fi

if [ $(( $(date +%s) - $(date -r /tmp/lastrun +%s) )) -lt 420 ] ; then
     # The minimum interval of 7 minutes between successive batches hasn't passed yet.
    exit 0
fi

####  Start running your actual batch job below

/path/to/your/command

#### actual batch job is done, now update the time stamp
date > /tmp/lastrun
#EOF

Що ви можете безпечно (намагатися) запускати щохвилини:

* * * * * /path/to/your/seven-minute-job

Інший, але подібна проблема буде запланувати пакет для запуску в перший понеділок кожного місяця (або в другу середу) і т.д. Просто запланувати пакет для запуску щопонеділка і вихід , коли дата не є ні між 1 - го або 7 - го і день тижня не понеділок.

#!/bin/bash
# first-monday-of-the-month-housekeeping-job

# exit if today is not a Monday (and prevent locale issues by using the day number) 
if [ $(date +%u) != 1 ] ; then
  exit 0
fi

# exit if today is not the first Monday
if [ $(date +%d) -gt 7 ] ; then
  exit 0
fi

####  Start running your actual batch job below

/path/to/your/command

#EOF

Що ви можете сміливо (намагатися) запускати кожного понеділка:

0 0 * * 1 /path/to/your/first-monday-of-the-month-housekeeping-job

Не використовуйте cron

Якщо ваші потреби складні, ви можете розглянути можливість використання більш досконалого продукту, розробленого для запуску складних графіків (розподілених на декількох серверах), який підтримує тригери, залежність від роботи, обробку помилок, повторний моніторинг та повторний моніторинг тощо. Промисловий жаргон буде "підприємством " планування роботи та / або" автоматизація навантаження ".


8

Специфічний для PHP

Якщо у вас є робота на крон, наприклад:

php /bla/bla/something.php >> /var/logs/somelog-for-stdout.log

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

PHP за замовчуванням не надсилає помилки в STDOUT. @ see https://bugs.php.net/bug.php?id=22839

Щоб виправити це, додайте в phі.phіnі кліпу або у рядку (або у вашій баш-обгортці для PHP) такі:

  • - визначити display_startup_errors = 1
  • --define display_errors = 'stderr'

1-е налаштування дозволить вам мати фатальні випадки, такі як "Опції пам'яті", а 2-е - перенаправити їх на STDERR. Тільки після того, як ви зможете спати добре, всі будуть відправлені на кореневу пошту, а не щойно увійшли.


2
Цей звіт про помилку було закрито ще в 2007 році, і статус патча було додано до гілок PHP 5.2+. Ви впевнені, що це потрібно? Я просто спробував на PHP 5.4 і, здається, працює добре. (Він все ще потрібен для PHP 4).
Xeoncross

@Xeoncross див. Дату відповіді :)
gaRex

1
Так, саме це мене бентежило, коли ти відповів у 2013 році, а квиток був у 0707 році.
Ксеонкросс

0

Додавання моєї відповіді звідси для повноти та додавання іншого потенційно корисного ресурсу:

У cronкористувача є інше, $PATHніж у вас:

Часта проблема, яку користувачі роблять із crontabзаписами, - це те, що вони забувають, що це cronпрацює в інших, environmentніж у користувачів, які ввійшли в систему. Наприклад, користувач створює програму або скрипт у своєму $HOMEкаталозі та вводить наступну команду для запуску:

$ ./certbot ... 

Команда ідеально працює з його командного рядка. Потім користувач додає цю команду до своєї crontab, але вважає, що це не працює:

*/10 * * * * ./certbot ....

Причиною невдачі в цьому випадку є те, що ./для cronкористувача це місце інше, ніж для користувача, який увійшов у систему. Тобто, environmentінше! PATH є частиною environmentі, як правило, для cronкористувача. Ускладнює цю проблему те, що environmentfor cronне однаковий для всіх * nix- дистрибутивів, і існує кілька версійcron

Просте рішення цієї конкретної проблеми - дати cronкористувачеві повну специфікацію шляху у crontabзаписі:

0 22 * * * /path/to/certbot .....

Що таке cronкористувач environment?

У деяких випадках нам може знадобитися знати повну environmentспецифікацію для cronнашої системи (або нам може бути просто цікаво). Що environmentдля cronкористувача, і чим він відрізняється від нашого? Крім того, ми , можливо , повинні знати, environmentдля іншого cronкористувача - rootнаприклад , ... що це rootкористувач з environmentдопомогою cron? Один із способів дізнатися це - попросити cronсказати нам:

  1. Створіть сценарій оболонки у своєму домашньому каталозі ( ~/) наступним чином (або за допомогою редактора на ваш вибір):
$ nano ~/envtst.sh
  1. Введіть у редакторі після налаштування для вашої системи / користувача:
#!/bin/sh 
/bin/echo "env report follows for user "$USER >> /home/you/envtst.sh.out 
/usr/bin/env >> /home/you/envtst.sh.out 
/bin/echo "env report for user "$USER" concluded" >> /home/you/envtst.sh.out
/bin/echo " " >> /home/you/envtst.sh.out
  1. Збережіть файл, вийдіть із редактора та встановіть права доступу до файлу як виконувані.
$ chmod a+rx ~/envtst.sh
  1. Запустіть щойно створений сценарій та перегляньте результат у /home/you/envtst.sh.out. Цей результат покаже ваше поточне середовище, коли $USERви ввійшли як:
$ ./envtst.sh $$ cat /home/you/envtst.sh.out
  1. Відкрийте crontabдля редагування:
$ crontab -e -u root
  1. Введіть наступний рядок у нижній частині вашого тексту crontab:
* * * * *  /home/you/envtst.sh >> /home/you/envtst.sh.err 2>&1

ВІДПОВІДЬ: Вихідний файл /home/you/envtst.sh.outбуде містити перелік environmentдля "користувача root root". Як тільки ви це знаєте, відповідно коригуйте crontabзапис.

Я не можу вказати потрібний графік у моєму crontabзаписі:

Запис графіка для crontabпрограми, звичайно, визначено в man crontab, і ви повинні прочитати це. Однак читання man crontabта розуміння розкладу - це дві різні речі. І пробні помилки в специфікації розкладу можуть стати дуже стомлюючими. На щастя, є ресурс, який може допомогти: гуру кронтабу. . Введіть специфікацію розкладу, і він пояснить розклад простою англійською мовою.

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

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