Это Канонический вопрос об использовании cron и crontab.
Вас направили сюда, потому что сообщество совершенно уверено, что ответ на ваш вопрос можно найти ниже. Если ниже на ваш вопрос нет ответа, то ответы помогут вам собрать информацию, которая поможет сообществу помочь вам. Эта информация должна быть отредактирована в вашем исходном вопросе.
Ответ на 'Почему мой crontab не работает и как я могу устранить его?'можно увидеть ниже. Это касается cron
system с выделенным crontab.
Это вики сообщества, если вы заметили что-то неправильное в этом ответе или у вас есть дополнительная информация, отредактируйте ее.
Каждый пользователь в системе может иметь свой собственный файл 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 представлена одной строкой. Вы не можете использовать \
чтобы расширить команду на несколько строк. Хеш (#
Знак) представляет собой комментарий, который означает, что все в этой строке игнорируется 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 отправлял почту на другую учетную запись, вы можете установить переменную среды 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 не запущен, ваши команды не будут запланированы ...
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
Могут быть и другие методы; используйте то, что предоставляет ваш дистрибутив.
Количество доступных переменных среды, вероятно, будет очень ограниченным. Обычно вы определяете только несколько переменных, например $LOGNAME
, $HOME
, и $PATH
.
Особо следует отметить PATH
ограничено /bin:/usr/bin
. Подавляющее большинство проблем типа «мой скрипт cron не работает» вызвано этим ограничительным путем.. Если ваша команда находится в другом месте, вы можете решить эту проблему двумя способами:
Укажите полный путь к вашей команде.
1 2 * * * /path/to/your/command
Укажите подходящий ПУТЬ в файле crontab
PATH=/bin:/usr/bin:/path/to/something/else
1 2 * * * command
Если вашей команде требуются другие переменные среды, вы также можете определить их в файле crontab.
Независимо от того, где исполняемая программа находится в файловой системе, текущий рабочий каталог программы при запуске cron будет домашний каталог пользователя. Если вы обращаетесь к файлам в своей программе, вам необходимо принять это во внимание, если вы используете относительные пути или (желательно) просто везде используете полностью определенные пути, что избавит всех от путаницы.
Cron обычно требует, чтобы команды заканчивались новой строкой. Отредактируйте ваш crontab; перейти в конец строки, содержащей последнюю команду, и вставить новую строку (нажать Enter).
Вы не можете использовать пользовательский crontab в формате crontab для / etc / crontab или фрагментов в /etc/cron.d и наоборот. Форматированный пользователем crontab не включает имя пользователя в 6-й позиции строки, в то время как системный crontab включает имя пользователя и запускает команду от имени этого пользователя.
#!/bin/sh
вверху)Если ваша дата недавно была изменена пользователем или обновлением системы, часовым поясом или другим, то 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}
должен :
Последний регулярно причиняет боль ничего не подозревающим пользователям; в частности, любой сценарий в одной из этих папок с именем 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
Если ваши потребности сложны, вы можете рассмотреть возможность использования более продвинутого продукта, который предназначен для выполнения сложных расписаний (распределенных по нескольким серверам) и который поддерживает триггеры, зависимости заданий, обработку ошибок, повторные попытки и мониторинг повторных попыток и т. Д. Промышленным жаргоном будет «предприятие» " планирование работы и / или «автоматизация рабочей нагрузки».
Если у вас есть работа 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) следующее:
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
сказать нам:
~/
) следующим образом (или с помощью редактора по вашему выбору): $ nano ~/envtst.sh
#!/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
$ chmod a+rx ~/envtst.sh
/home/you/envtst.sh.out
. Этот вывод покажет вашу текущую среду как $USER
вы вошли как: $ ./envtst.sh $$ cat /home/you/envtst.sh.out
crontab
для редактирования: $ crontab -e -u root
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
записи, как вам нужно, чтобы получить нужное вам расписание.