Назад | Перейти на главную страницу

Почему мой crontab не работает и как я могу устранить его?

Это Канонический вопрос об использовании cron и crontab.

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

Ответ на 'Почему мой crontab не работает и как я могу устранить его?'можно увидеть ниже. Это касается cron system с выделенным crontab.

Как исправить все проблемы / проблемы, связанные с 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 не запущен, а дата / время выполнения команды уже прошли, crond не будет догонять и выполнять предыдущие запросы.

crontab подробности, как сформулировать команду:

Команда crontab представлена ​​одной строкой. Вы не можете использовать \ чтобы расширить команду на несколько строк. Хеш (#Знак) представляет собой комментарий, который означает, что все в этой строке игнорируется cron. Начальные пробелы и пустые строки игнорируются.

Будьте ОЧЕНЬ осторожны при использовании процентов (%) войдите в свою команду. Если они не сбежали \% они преобразуются в символы новой строки и все после первого неэкранированного % передается вашей команде на стандартный ввод.

Есть два формата файлов crontab:

  • Пользовательские 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 регистрирует свои действия через системный журнал, который (в зависимости от ваших настроек) часто попадает в /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. Подавляющее большинство проблем типа «мой скрипт cron не работает» вызвано этим ограничительным путем.. Если ваша команда находится в другом месте, вы можете решить эту проблему двумя способами:

  1. Укажите полный путь к вашей команде.

     1 2 * * * /path/to/your/command
    
  2. Укажите подходящий ПУТЬ в файле crontab

     PATH=/bin:/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")"

Остерегайтесь Судо

при работе от имени пользователя без полномочий root,

crontab -e

откроет crontab пользователя, а

sudo crontab -e

откроет crontab пользователя root. Не рекомендуется запускать команды sudo в задании cron, поэтому, если вы пытаетесь запустить команду sudo в cron пользователя, попробуйте переместить эту команду в cron root и удалить sudo из команды.

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

  • принадлежать root
  • быть доступным для записи только root
  • не может быть записано группой или другими пользователями
  • иметь имя без точек ». или любой другой специальный символ, кроме «-» и «_».

Последний регулярно причиняет боль ничего не подозревающим пользователям; в частности, любой сценарий в одной из этих папок с именем whatever.sh, mycron.py, testfile.plи т. д. будут не быть казненным, когда-либо.

По моему опыту, именно этот момент был наиболее частой причиной невыполнения задания cron в Debian и производных.

Видеть man cron для получения более подробной информации, если необходимо.

Если ваши cronjobs перестают работать, убедитесь, что срок действия вашего пароля не истек., Так как после этого все cron-задания останавливаются.
Будут сообщения в /var/log/messages аналогично приведенному ниже, в котором показаны проблемы с аутентификацией пользователя:

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

Необычные и нерегулярные графики

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 и т.д.).


Что делать вместо этого?

Создать несколько партий

Вместо одного задания cron создайте несколько пакетов, которые вместе приведут к желаемому расписанию.

Например, чтобы запускать пакет каждые 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 минут.

Чаще запускайте свои партии (но предотвратить одновременное выполнение нескольких пакетов)

Многие нечетные расписания развиваются из-за того, что время выполнения партии увеличивается / изменяется, а затем партии планируются с небольшим дополнительным запасом прочности, чтобы предотвратить перекрытие и одновременное выполнение последующих запусков одной и той же партии.

Вместо этого подумайте иначе и создайте задание cron, которое будет корректно завершаться ошибкой, если предыдущий запуск еще не завершен, но которое будет выполняться в противном случае. Посмотри это Вопросы и ответы:

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

Это почти сразу же запустит новый запуск после завершения предыдущего запуска / usr / local / bin / partial_cron_job.

Чаще запускайте свои партии (но выходите изящно, когда условия не подходят)

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

В баше seven-minute-job тогда будет выглядеть примерно так:

#!/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ул или 7th и день недели не понедельник.

#!/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

Если ваши потребности сложны, вы можете рассмотреть возможность использования более продвинутого продукта, который предназначен для выполнения сложных расписаний (распределенных по нескольким серверам) и который поддерживает триггеры, зависимости заданий, обработку ошибок, повторные попытки и мониторинг повторных попыток и т. Д. Промышленным жаргоном будет «предприятие» " планирование работы и / или «автоматизация рабочей нагрузки».

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

Если у вас есть работа cron, например:

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

И в случае ошибок ожидайте, что они будут вам отправлены, а они нет - проверьте это.

PHP по умолчанию не отправляет ошибки в STDOUT. @видеть https://bugs.php.net/bug.php?id=22839

Чтобы исправить это, добавьте в cli php.ini или в свою строку (или в оболочку bash для PHP) следующее:

  • --define display_startup_errors = 1
  • --define display_errors = 'stderr'

1-я настройка позволит вам иметь фатальные ошибки, такие как 'Memory oops', а 2-я - перенаправить их всех в STDERR. Только после того, как вы выспитесь, все будет отправлено на почту вашего root, а не просто зарегистрировано.

Добавление моего ответа отсюда для полноты и добавления еще одного потенциально полезного ресурса:

В cron у пользователя другой $PATH чем вы это делаете:

Пользователи часто сталкиваются с проблемой crontab записи в том, что они забывают, что cron работает в другом environment чем они делают как зарегистрированный пользователь. Например, пользователь создает программу или скрипт в своем $HOME каталог и вводит следующую команду для его запуска:

$ ./certbot ... 

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

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

Причина отказа в данном случае в том, что ./ это другое место для cron пользователя, чем для вошедшего в систему пользователя. Это environment отличается! PATH является частью environment, а для cron пользователь. Проблема усложняется тем, что environment для 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 cron". Как только вы это узнаете, настройте crontab запись соответственно.

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

Запись в расписании для crontab конечно определяется в man crontab, и вы должны это прочитать. Однако чтение man crontab, и понимание расписания - разные вещи. А метод проб и ошибок по спецификации расписания может стать очень утомительно. К счастью, есть ресурс, который может помочь: гуру crontab.. Введите спецификацию вашего расписания, и оно объяснит расписание на простом английском языке.

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