Почему не работают скрипты crontab?

Часто, crontab сценарии не выполняются по расписанию или как ожидается. Для этого есть множество причин:

  1. неправильная запись crontab
  2. проблема с разрешениями
  3. переменные среды

Вики-сообщество призвано объединить основные причины crontab сценарии не выполняются, как ожидалось. Запишите каждую причину в отдельном ответе.

Пожалуйста, включите одну причину для ответа - подробности о том, почему он не выполнен - ​​и исправьте (и) по этой одной причине.

Пожалуйста, пишите только специфичные для cron проблемы, например команды, которые выполняются как ожидается от оболочки, но ошибочно выполняются cron.

47 ответов

Решение

Другая среда

Cron передает минимальный набор переменных среды для ваших заданий. Чтобы увидеть разницу, добавьте фиктивную работу вот так:

* * * * * env> /tmp/env.output

Ждать /tmp/env.output чтобы быть созданным, затем удалите работу снова. Теперь сравните содержимое /tmp/env.output с выходом env запустить в своем обычном терминале.

Распространенная "гоча" здесь PATH Переменная окружения отличается. Может быть, ваш скрипт cron использует команду somecommand нашел в /opt/someApp/bin, который вы добавили в PATH в /etc/environment? Крон игнорирует PATH из этого файла, так что бег somecommand из вашего скрипта не получится при запуске с cron, но сработает при запуске в терминале. Стоит отметить, что переменные из /etc/environment будут переданы заданиям cron, но не переменным, которые специально устанавливает сам cron, таким как PATH,

Чтобы обойти это, просто установите свой собственный PATH переменная в верхней части скрипта. Например

#!/bin/bash
PATH=/opt/someApp/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# rest of script follows

Некоторые предпочитают просто использовать абсолютные пути ко всем командам. Я рекомендую против этого. Подумайте, что произойдет, если вы хотите запустить свой скрипт в другой системе, и в этой системе команда находится в /opt/someAppv2.2/bin вместо. Вам придется пройти весь сценарий, заменив /opt/someApp/bin с /opt/someAppv2.2/bin вместо того, чтобы делать небольшое редактирование в первой строке скрипта.

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

PATH=/opt/someApp/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

15 1 * * * backupscript --incremental /home /root

Мой главный вопрос: если вы забудете добавить новую строку в конце crontab файл. Другими словами, файл crontab должен заканчиваться пустой строкой.

Ниже приведен соответствующий раздел в справочных страницах по этому вопросу (man crontab потом переходи до конца)

   Although cron requires that each entry in a crontab end  in  a  newline
   character,  neither the crontab command nor the cron daemon will detect
   this error. Instead, the crontab will appear to load normally. However,
   the  command  will  never  run.  The best choice is to ensure that your
   crontab has a blank line at the end.

   4th Berkeley Distribution      29 December 1993               CRONTAB(1)

Cron демон не работает. Я действительно облажался с этим несколько месяцев назад.

Тип:

pgrep cron 

Если вы не видите номера, значит, cron не запущен. sudo /etc/init.d/cron start можно использовать для запуска cron.

РЕДАКТИРОВАТЬ: Вместо того, чтобы вызывать сценарии инициализации через /etc/init.d, используйте служебную утилиту, например

sudo service cron start

Имя файла скрипта в cron.d/, cron.daily/, cron.hourly/и т. д., не должны содержать точку (.), иначе run-parts пропустит их.

Смотрите run-parts(8):

   If neither the --lsbsysinit option nor the --regex option is given then
   the names must consist entirely of upper and lower case  letters,  dig‐
   its, underscores, and hyphens.

   If  the  --lsbsysinit  option  is given, then the names must not end in
   .dpkg-old  or .dpkg-dist or .dpkg-new or .dpkg-tmp, and must belong  to
   one  or more of the following namespaces: the LANANA-assigned namespace
   (^[a-z0-9]+$);   the   LSB   hierarchical   and   reserved   namespaces
   (^_?([a-z0-9_.]+-)+[a-z0-9]+$);  and  the  Debian cron script namespace
   (^[a-zA-Z0-9_-]+$).

Итак, если у вас есть скрипт cron backup.sh, analyze-logs.pl в cron.daily/ каталог, вам лучше удалить имена расширений.

Во многих средах cron выполняет команды, используя shв то время как многие люди предполагают, что он будет использовать bash,

Предложения для проверки или исправления ошибки команды:

  • Попробуйте запустить команду в sh чтобы увидеть, работает ли это:

    sh -c "mycommand"
    
  • Оберните команду в подоболочку bash, чтобы убедиться, что она запускается в bash:

    bash -c "mybashcommand"
    
  • Скажите cron запустить все команды в bash, установив оболочку в верхней части вашего crontab:

    SHELL=/bin/bash
    
  • Если команда является скриптом, убедитесь, что скрипт содержит шебанг:

    #!/bin/bash
    

У меня были некоторые проблемы с часовыми поясами. Cron работал со свежим часовым поясом установки. Решение было перезапустить cron:

sudo service cron restart

Абсолютный путь должен использоваться для скриптов:

Например, /bin/grep следует использовать вместо grep:

# m h  dom mon dow   command
0 0 *  *  *  /bin/grep ERROR /home/adam/run.log &> /tmp/errors

Вместо:

# m h  dom mon dow   command
0 0 *  *  *  grep ERROR /home/adam/run.log &> /tmp/errors

Это особенно сложно, потому что та же команда будет работать при запуске из оболочки. Причина в том, что cron не имеет то же самое PATH переменная окружения как пользователь.

Если ваша команда crontab имеет % символ в этом, cron пытается интерпретировать это. Так что, если вы использовали какую-либо команду с % в нем (например, указание формата для команды date) вам необходимо его избежать.

Это и другие хорошие ошибки здесь:
http://www.pantz.org/software/cron/croninfo.html

Cron вызывает скрипт, который не является исполняемым.

Запустив chmod +x /path/to/scrip скрипт становится исполняемым и должен решить эту проблему.

Также возможно, что срок действия пароля пользователя истек. Даже пароль root может истечь. Вы можете tail -f /var/log/cron.log и вы увидите сбой cron с истекшим сроком действия пароля. Вы можете установить пароль, чтобы никогда не истек, делая это: passwd -x -1 <username>

В некоторых системах (Debian, Ubuntu) ведение журнала для cron не включено по умолчанию. В /etc/rsyslog.conf или /etc/rsyslog.d/50-default.conf строка:

# cron.*                          /var/log/cron.log

следует отредактировать (sudo nano /etc/rsyslog.conf) оставлено без комментариев:

cron.*                          /var/log/cron.log

После этого вам нужно перезапустить rsyslog через

/etc/init.d/rsyslog restart

или же

service rsyslog restart 

Источник: Включить ведение журнала crontab в Debian Linux

В некоторых системах (Ubuntu) отдельный файл регистрации для cron не включен по умолчанию, но связанные с cron журналы появляются в файле syslog. Можно использовать

cat /var/log/syslog | grep cron -i

для просмотра сообщений, связанных с cron.

Если ваш cronjob вызывает GUI-приложения, вы должны сообщить им, какой DISPLAY они должны использовать.

Пример: запуск Firefox с помощью cron.

Ваш скрипт должен содержать export DISPLAY=:0 где-то.

Небезопасное разрешение таблицы cron

Таблица cron отклоняется, если ее разрешение небезопасно

sudo service cron restart
grep -i cron /var/log/syslog|tail -2
2013-02-05T03:47:49.283841+01:00 ubuntu cron[49906]: (user) INSECURE MODE (mode 0600 expected) (crontabs/user)

Проблема решена с

# correct permission
sudo chmod 600 /var/spool/cron/crontabs/user
# signal crond to reload the file
sudo touch /var/spool/cron/crontabs

Боюсь, проблемы с разрешениями встречаются довольно часто.

Обратите внимание, что распространенным обходным решением является выполнение всего, используя crontab root, который иногда является действительно плохой идеей. Установка правильных разрешений - определенно упущенная проблема.

Сценарий зависит от местоположения. Это связано с тем, что в скрипте всегда используются абсолютные пути, но это не совсем одно и то же. Ваша работа cron может потребоваться cd перед запуском в конкретный каталог, например, задача rake в приложении Rails может потребоваться в корне приложения для Rake, чтобы найти правильную задачу, не говоря уже о соответствующей конфигурации базы данных и т. д.

Итак, запись в crontab

23 3 * * * /usr/bin/rake db:session_purge RAILS_ENV=production

будет лучше как

23 3 * * * cd /var/www/production/current && /usr/bin/rake db:session_purge RAILS_ENV=production

Или, чтобы сделать запись в crontab более простой и менее хрупкой:

23 3 * * * /home/<user>/scripts/session-purge.sh

со следующим кодом в /home/<user>/scripts/session-purge.sh:

cd / var / www / production / current
/ usr / bin / rake db: session_purge RAILS_ENV = production

Спецификации Crontab, которые работали в прошлом, могут сломаться при перемещении из одного файла crontab в другой. Иногда причина в том, что вы переместили спецификацию из системного файла crontab в пользовательский файл crontab или наоборот.

Формат спецификации задания cron отличается в файлах crontab пользователей (/var/spool/cron/username или /var/spool/cron/crontabs/username) и системных crontabs (/etc/crontab и файлы в /etc/cron.d).

Системные crontabs имеют дополнительное поле 'user' прямо перед командой для запуска.

Это приведет к ошибкам с указанием таких вещей, как george; command not found когда вы перемещаете команду из /etc/crontab или файл в /etc/cron.d в файл crontab пользователя.

И наоборот, cron будет выдавать такие ошибки, как /usr/bin/restartxyz is not a valid username или подобное, когда происходит обратное.

Самая частая причина, по которой я видел сбой cron в неверно указанном расписании. Требуется практика, чтобы указать работу, запланированную на 23:15 как 30 23 * * * вместо * * 11 15 * или же 11 15 * * *, День недели для рабочих мест после полуночи также сбивается с толку 2-6 после полуночи нет 1-5, Конкретные даты обычно являются проблемой, так как мы редко их используем * * 3 1 * не 3 марта.

Если вы работаете с различными платформами, используя неподдерживаемые параметры, такие как 2/3 во времени спецификации также могут вызвать сбои. Это очень полезная опция, но она не всегда доступна. Я также сталкивался с проблемами, такие как списки 1-5 или же 1,3,5,

Использование неквалифицированных путей также вызвало проблемы. Путь по умолчанию обычно /bin:/usr/bin поэтому будут выполняться только стандартные команды. Эти каталоги обычно не имеют желаемой команды. Это также влияет на сценарии, использующие нестандартные команды. Другие переменные среды также могут отсутствовать.

Полное уничтожение существующего crontab вызвало у меня проблемы. Я сейчас загружаю из файла копию. Это можно восстановить из существующего crontab, используя crontab -l если это будет забито Я храню копию crontab в ~/bin. Это комментируется повсюду и заканчивается строкой # EOF, Это загружается ежедневно из записи в crontab, например:

#! / USR / бен / кронтаб
# Перезагрузить этот crontab
#
54 12    *   *   *   ${HOME}/bin/crontab

Приведенная выше команда reload опирается на исполняемый файл crontab с путём взрыва, на котором выполняется crontab. В некоторых системах требуется запуск crontab в команде и указание файла. Если каталог является сетевым, то я часто использую crontab.$(hostname) как имя файла. Это в конечном итоге исправит случаи, когда неправильный crontab загружается на неправильный сервер.

Использование файла обеспечивает резервное копирование того, каким должен быть crontab, и позволяет выполнять временные изменения (единственный раз, когда я использую crontab -e) для автоматического возврата. Доступны заголовки, которые помогают правильно настроить параметры планирования. Я добавил их, когда неопытные пользователи будут редактировать crontab.

Редко я сталкивался с командами, которые требуют ввода пользователя. Они терпят неудачу при crontab, хотя некоторые будут работать с перенаправлением ввода.

Если у вас есть такая команда:

* * * * * /path/to/script >> /tmp/output

и это не работает, и вы не можете видеть какой-либо вывод, это не обязательно означает, что cron не работает. Сценарий может быть поврежден, и вывод будет передан в stderr, который не будет передан в / tmp / output. Проверьте, что это не так, записав этот вывод:

* * * * * /path/to/script >> /tmp/output 2>&1

чтобы увидеть, поможет ли это вам решить вашу проблему.

Сценарий cron вызывает команду с параметром --verbose

У меня произошел сбой скрипта cron, потому что я набирал скрипт на автопилоте и включил опцию --verbose:

#!/bin/bash
some commands
tar cvfz /my/archive/file.tar.gz /my/shared/directory
come more commands

Сценарий выполнялся нормально при выполнении из оболочки, но не работал при запуске из crontab, поскольку подробный вывод выводится на стандартный вывод при запуске из оболочки, но нигде при запуске из crontab. Легко исправить, чтобы удалить "V":

#!/bin/bash
some commands
tar cfz /my/archive/file.tar.gz /my/shared/directory
some more commands

Если вы получаете доступ к учетной записи с помощью ключей SSH, можно войти в учетную запись, но не заметить, что пароль учетной записи заблокирован (например, из-за истечения срока действия или попытки ввода неверного пароля)

Если система использует PAM и учетная запись заблокирована, это может остановить запуск cronjob. (Я проверял это на Solaris, но не на Ubuntu)

Подобные сообщения вы можете найти в /var/adm/messages:

24 октября 07:51:00 mybox cron[29024]: [ID 731128 auth.notice] pam_unix_account: cron пытается проверить заблокированный аккаунт myuser с локального хоста
24 октября, 07:52:00 mybox cron[29063]: [ID 731128 auth.notice] pam_unix_account: cron пытается проверить заблокированный аккаунт myuser с локального хоста
24 октября 07:53:00 mybox cron[29098]: [ID 731128 auth.notice] pam_unix_account: cron пытается проверить заблокированный аккаунт myuser с локального хоста
24 октября, 07:54:00 mybox cron[29527]: [ID 731128 auth.notice] pam_unix_account: cron пытается проверить заблокированный аккаунт myuser с локального хоста

Все, что вам нужно сделать, это запустить:

# passwd -u <ИМЯ ПОЛЬЗОВАТЕЛЯ>

как root, чтобы разблокировать учетную запись, и crontab должен снова работать.

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

Я создал файл mycronjob с расписанием cron, именем пользователя и командой и скопировал его в /etc/cron.d каталог. Мои две ошибки:

  1. mycronjob файл должен был принадлежать пользователю root для запуска
  2. Я должен был установить права доступа к файлу 644 - 664 не будет работать.

Проблема с разрешением появится в /var/log/syslog как то похожее на:

Apr 24 18:30:01 ip-11-22-33-44 cron[40980]: (*system*) INSECURE MODE (group/other writable) (/etc/crontab)
Apr 24 18:30:01 ip-11-22-33-44 cron[40980]: (*system*) INSECURE MODE (group/other writable) (/etc/cron.d/user)

Первая строка относится к /etc/crontab файл, а затем в файл, который я поместил под /etc/cront.d,

=== Предупреждение Docker ===

Если вы используете докер,

Я считаю правильным добавить, что мне не удалось заставить cron работать в фоновом режиме.

Для запуска задания cron внутри контейнера я использовал supervisor и запустил cron -fвместе с другим процессом.

Изменить: Еще одна проблема - мне также не удалось заставить его работать при запуске контейнера с сетью HOST. Смотрите эту проблему здесь также: https://github.com/phusion/baseimage-docker/issues/144

Если вы отредактировали свой файл crontab с помощью редактора Windows (через samba или что-то еще), и он заменил символы новой строки на \ n \ r или просто \ r, cron не запустится.

Кроме того, если вы используете /etc/cron.d/* и в одном из этих файлов есть \ r, cron будет перемещаться по файлам и останавливаться, когда попадет в плохой файл. Не уверен, что это проблема?

Использование:

od -c /etc/cron.d/* | grep \r

Cron-демон может быть запущен, но на самом деле не работает. Попробуйте перезапустить cron:

sudo /etc/init.d/cron restart

Когда задача запускается в cron, stdin закрывается. Программы, которые работают по-разному в зависимости от того, доступен ли stdin или нет, будут вести себя по-разному между сеансом оболочки и в cron.

Примером является программа goaccess для анализа файлов журнала веб-сервера. Это не работает в cron:

goaccess -a -f /var/log/nginx/access.log > output.html

а также goaccess показывает страницу справки вместо создания отчета. В оболочке это можно воспроизвести с помощью

goaccess -a -f /var/log/nginx/access.log > output.html < /dev/null

Исправление для goaccess заставить его читать журнал из stdin вместо чтения из файла, поэтому решение состоит в том, чтобы изменить запись crontab на

cat /var/log/nginx/access.log | goaccess -a > output.html

Основываясь на том, что Аарон Пирт упомянул о подробном режиме, иногда сценарии, не находящиеся в подробном режиме, будут инициализироваться, но не завершаться, если поведение включенной команды по умолчанию будет выводить строку или более на экран после запуска процедуры. Например, я написал сценарий резервного копирования для нашей интрасети, который использовал curl, утилиту, которая загружает или загружает файлы на удаленные серверы, и это очень удобно, если вы можете получить доступ к указанным удаленным файлам только через HTTP. Использование 'curl http://something.com/somefile.xls' приводило к зависанию написанного мной скрипта, который никогда не завершался, поскольку он выплевывал новую строку, за которой следовала строка прогресса. Мне пришлось использовать флаг без вывода сообщений (-s), чтобы запретить выводить какую-либо информацию, и написать собственный код для обработки, если файл не удалось загрузить.

Запись в cron через "crontab -e" с аргументом username в строке. Я видел примеры пользователей (или системных администраторов), пишущих свои сценарии оболочки и не понимающих, почему они не автоматизируют. Аргумент "пользователь" существует в /etc/crontab, но не в пользовательских файлах. так, например, ваш личный файл будет выглядеть примерно так:

# m h dom mon dow command

* * */2  *   *  /some/shell/script

тогда как / etc / crontab будет:

# m h dom mon dow user   command

* * */2  *   *  jdoe   /some/shell/script

Итак, почему вы делаете последнее? Ну, в зависимости от того, как вы хотите установить свои разрешения, это может стать очень запутанным. Я написал сценарии для автоматизации задач для пользователей, которые не разбираются в тонкостях или не хотят беспокоиться о тяжелой работе. Установив разрешения для --x------Я могу сделать сценарий исполняемым без возможности его чтения (и, возможно, случайного изменения). Тем не менее, я мог бы захотеть запустить эту команду с несколькими другими из одного файла (таким образом, облегчая поддержку), но удостовериться, что выходной файл назначен правильному владельцу. Это (по крайней мере, в Ubuntu 10.10) устраняет как невозможность чтения файла, так и выполнения, а также вышеупомянутую проблему с помещением точек в /etc/crontab (что, как ни странно, не вызывает ошибок при прохождении crontab -e).

В качестве примера я видел случаи sudo crontab -e используется для запуска скрипта с правами суперпользователя, с соответствующим chown username file_output в сценарии оболочки. Небрежно, но это работает. ИМХО, более изящный вариант это положить в /etc/crontab с объявленным именем пользователя и соответствующими разрешениями, так file_output едет в нужное место и хозяину.

Файлы.bashrc по умолчанию в UBuntu 16.04 (и во многих других версиях) имеют встроенный механизм, который ничего не делает, если они не являются интерактивной оболочкой.

Это может помешать правильному источнику файла в скрипте, который запускается cron! Чтобы предотвратить это, закомментируйте следующие строки в верхней части вашего файла.bashrc:

Ubuntu 16.04

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

Ubuntu 12.04 и некоторые другие версии

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

До тех пор, пока они остаются, если cron запускает скрипт, который получает ваш файл.bashrc, вы фактически не получите никаких переменных окружения, к которым вы привыкли, внутри вашего терминала!

В 16.04, если у вас есть эта ошибка в системном журнале

(CRON) error (can't fork)

пытаться:

systemctl status cron.service

В результате:

Tasks: num_task (limit: 512)

Если num_task близко к пределу использования:

systemctl set-property cron.service TasksMax=new_max

замещать new_max с подходящим значением.

Хотя вы можете определять переменные окружения в вашем crontable, вы не находитесь в сценарии оболочки. Поэтому конструкции, подобные следующим, не будут работать:

SOME_DIR=/var/log
MY_LOG_FILE=${SOME_LOG}/some_file.log

BIN_DIR=/usr/local/bin
MY_EXE=${BIN_DIR}/some_executable_file

0 10 * * * ${MY_EXE} some_param >> ${MY_LOG_FILE}

Это потому, что переменные не интерпретируются в crontable: все значения принимаются буквально. И это то же самое, если вы опустите скобки. Таким образом, ваши команды не будут выполняться, а ваши файлы журнала не будут записаны...

Вместо этого вы должны определить все переменные окружения прямо:

SOME_DIR=/var/log
MY_LOG_FILE=/var/log/some_file.log

BIN_DIR=/usr/local/bin
MY_EXE=/usr/local/bin/some_executable_file

0 10 * * * ${MY_EXE} some_param >> ${MY_LOG_FILE}

Задания Cron не будут выполняться, если срок действия пароля вашего пользователя истек.

Одним из признаков этого является, если ваш журнал хрон (как правило, /var/log/syslog в Ubuntu, я считаю) содержит сообщения типа "Токен аутентификации больше не действителен; требуется новый".

Вы можете проверить эту проблему, запустив sudo chage -l the_username,

Вот пример просроченного пароля:

$ sudo chage -l root
Last password change                    : password must be changed
Password expires                    : password must be changed
Password inactive                   : password must be changed
Account expires                     : never
Minimum number of days between password change      : 0
Maximum number of days between password change      : 14600
Number of days of warning before password expires   : 14

Исправление заключается в изменении пароля. Например:

sudo -u root passwd

Затем следуйте инструкциям, указав новый пароль в соответствии с запросом.

Спасибо https://serverfault.com/questions/449651/why-is-my-crontab-not-working-and-how-can-i-troubleshoot-it за указание меня в правильном направлении здесь. В моем случае, так же, как и для этого комментатора, это был пользователь root для коробки DigitalOcean.

Другие вопросы по тегам