Cron (Русский)
Из Википедии:
cron - классический демон-планировщик задач в UNIX-подобных операционных системах, использующийся для периодического выполнения заданий в определённое время. Регулярные действия описываются инструкциями, помещенными в файлы crontab и в специальные директории.
Contents
Установка
Существует множество реализаций cron, но ни одна из них не устанавливается по умолчанию, т.к. система использует вместо него systemd/Timers. См. руководство по cron для Gentoo, в котором представлены сравнения.
Доступные пакеты:
- cronie
- fcron
- bcronAUR[ссылка недействительна: сохранено в aur-mirror]
- dcronAUR
- vixie-cronAUR
- scron-gitAUR
Настройка
Активация и автозапуск
После установки демон не будет включен по умолчанию. Установленный пакет устанавливает службу, которая может контролироваться systemctl. Например, для cronie это cronie.service
.
Текущие активные задания расположены в папках вроде /etc/cron.daily/
и запуск службы cron активирует их все.
0anacron
, которая осуществляют отложенный запуск других задач, например, если компьютер был выключен во время срабатывания задачи по расписанию.Обработка ошибок в заданиях
cron регистрирует стандартный вывод из stdout и stderr и пытается отправить его на электронную почту пользователя используя команду sendmail
. В cronie такие сообщения на электронную почту отключены, если отсутствует файл /usr/bin/sendmail
. Для того, чтобы электронные письма направлялись пользователю, в системе должен быть запущен smtp-демон, например opensmtpd. Также вы можете установить пакет, который предоставляет команду sendmail и настроить его на отсылку почту удаленному адресату. Ну и наконец, вы можете вести лог при помощи команды -m
и скрипта.
Пример с msmtp
Установите пакет msmtp-mta, который создаст символическую ссылку с /usr/bin/sendmail
на /usr/bin/msmtp
. Перезапустите cronie
, чтобы убедиться, что служба обнаружила новую команду sendmail
. Теперь вам нужно как-то конвертировать для msmtp
ваше имя пользователя в адрес электронной почты.
Затем либо добавьте строку MAILTO
в файл crontab, например, так:
MAILTO=your@email.com
либо создайте файл /etc/msmtprc
и напишите в него строку:
aliases /etc/aliases
Создайте файл /etc/aliases
:
your_username: your@email.com # Optional: default: your@email.com
Затем измените конфигурацию демона cronie заменив команду ExecStart
на:
ExecStart=/usr/bin/crond -n -m '/usr/bin/msmtp -t'
Пример с esmtp
После установки настройте транспорт почты:
/etc/esmtprc
identity myself@myisp.com hostname mail.myisp.com:25 username "myself" password "secret" starttls enabled default mda "/usr/bin/procmail -d %T"
Для работы в режиме доставки Procmail требует права суперпользователя, но это не проблема, т.к. вы все равно запускаете задания cron от имени root.
Чтобы проверить, что все работает, создайте файл message.txt
с "test message"
внутри.
Из той же папки запустите:
$ sendmail user_name < message.txt
Затем:
$ cat /var/spool/mail/user_name
Вы должны увидеть тестовое сообщение, а также время и дату его отправки.
Поток ошибок всех активных заданий теперь перенаправлен в /var/spool/mail/user_name
.
В связи с ограничениями прав, довольно непросто создавать и отправлять электронные письма пользователю root (например, так: su -c ""
). В esmtp
можно настроить пересылку сообщений, адресованных root, обычному пользователю:
/etc/esmtprc
force_mda="user-name"
~/.esmtprc
с тем же содержанием.Выполните следующую команду, чтобы дать необходимые права:
$ chmod 710 ~/.esmtprc
Затем повторите тест с отправкой message.txt
точно так же, как описано выше.
Пример с opensmtpd
Установите opensmtpd.
Отредактируйте /etc/smtpd/smtpd.conf
. Следующая конфигурация подходит для локальной доставки почты:
listen on localhost accept for local deliver to mbox
Можете начинать тестировать ее. Для начала запустите smtpd.service
. Затем:
$ echo test | sendmail user
user может проверить свою почту любым клиентом, способным распознать формат mbox, либо просто посмотреть файл /var/spool/mail/user
. Если все прошло нормально, можете
включить opensmtpd.
Этот метод имеет то преимущество, что не нужно отправлять уведомления cron на удаленный сервер, не нужно даже никакого сетевого соединения. С другой стороны, в памяти системы висит еще один демон.
- На момент написания статьи пакет opensmtpd не создает все необходимые папки в
/var/spool/smtpd
, но демон предупредит об этом, указав все необходимые права и владельцев. Просто создайте нужные папки самостоятельно. - Даже несмотря на то, что предложенная конфигурация не принимает удаленные подключения, хорошей практикой является добавить дополнительный слой безопасности, заблокировав порт 25 в iptables или другом файерволле.
Длительные задания cron
Представьте, что в cron загружена следующая программа:
#!/bin/sh echo "I had a recoverable error!" sleep 1h
Что произойдет?
- cron запускает скрипт
- как только cron видит какой-то вывод, он запускает вашу почтовую систему и создает некоторые заголовки. Он оставляет поток открытым, потому что задание не завершено и может быть больше выходных данных.
- почтовая система открывает соединение с postfix и оставляет его открытым, пока ждет окончания тела письма.
- postfix закрывает простаивающее соединение раньше, чем проходит один час, и вы получаете ошибку вроде этой:
smtpmsg='421 … Error: timeout exceeded' errormsg='the server did not accept the mail'
Для того, чтобы решить эту проблему, вам понадобятся команды chronic или sponge из пакета moreutils.
С их man-страниц:
- chronic
- chronic запускает команду и организовывает ее стандартные потоки вывода и ошибок так, что отображается только неправильный результат работы программы (выход с ненулевым значением или сбой). Если команда выполнена успешно, любые дополнительные выходные данные будут скрыты.
- sponge
- sponge получает стандартный входной поток и пишет его в специальный файл. В отличие от перенаправления командной строки, sponge аггрегирует весь свой входной поток в выходной файл. Если выходной файл не указан, sponge выводит данные в stdout.
Даже если это не указано явно, chronic буферизирует выходные данные команды перед тем, как открыть stdout (как и sponge)
Формат crontab
Основной формат для crontab таков:
минута час день_месяца месяц день_недели команда
- минута - значение от 0 до 59
- час - значение от 0 до 23
- день_месяца - значение от 1 до 31
- месяц - значение от 1 до 12
- день_недели - значение от 0 до 6, где 0 - это воскресенье.
Несколько вызовов могут быть перечислены через запятую, интервал может быть задан через дефис, а звёздочка означает любой символ. Пробелы используются для разделения полей. К примеру, строка
*/5 9-16 * 1-5,9-12 1-5 ~/bin/i_love_cron.sh
вызовет скрипт i_love_cron.sh
каждые пять минут с 9 AM до 4:55 PM по будням (уточнить, неделя может начинаться с воскресенья) кроме летних месяцев (июнь, июль, август). Больше примеров и дополнительные настройки могут быть найдены ниже.
Базовые команды
Crontabs никогда не редактируются напрямую; вместо этого пользователи должны использовать crontab
утилиту для работы со своими crontabs. Чтобы получить доступ к этой утилите, пользователь должен быть членом группы users
(смотри команду gpasswd
).
Чтобы просмотреть свои crontabs, пользователь может воспользоваться коммандой:
$ crontab -l
Для редактирования своих crontabs:
$ crontab -e
crontab
использует редактор vi
. Чтобы изменить это, экспортируйте EDITOR
или VISUAL
, или укажите редактор напрямую: EDITOR=vim crontab -e
.Чтобы удалить свои crontabs:
$ crontab -r
Если пользователь имеет сохранённые crontab и хочет полностью перезаписать свои старые crontab, он может воспользоваться:
$ crontab saved_crontab_filename
Чтобы перезаписать crontab из командной строки (Wikipedia:stdin), используйте
$ crontab -
Чтобы отредактировать чьи-либо ещё crontab, вызовите следующую команду из под root:
# crontab -u username -e
Этот же формат (присоединяя -u username
к команде) работает так же для чтения и удаления crontabs.
Примеры
Запись:
01 * * * * /bin/echo Hello, world!
выполняет команду /bin/echo Hello, world!
в первую минуту каждого часа каждого дня (т.е. в 12:01, 1:01, 2:01, etc.).
Аналогично:
*/5 * * jan mon-fri /bin/echo Hello, world!
выполняет то же действие каждые пять минут по будним дням в течение Января (т.е. в 12:00, 12:05, 12:10, etc.).
Строка (как указано в "man 5 crontab"):
*0,*5 9-16 * 1-5,9-12 1-5 /home/user/bin/i_love_cron.sh
вызывает скрипт i_love_cron.sh
в пятиминутные интервалы с 9 AM до 5 PM (не включая 5 PM) каждый будний день каждого месяца, кроме летних.
Periodical settings can also be entered as in this crontab template:
# Chronological table of program loadings # Edit with "crontab" for proper functionality, "man 5 crontab" for formatting # User: johndoe # mm hh DD MM W /path/progam [--option]... ( W = weekday: 0-6 [Sun=0] ) 21 01 * * * /usr/bin/systemctl hibernate @weekly $HOME/.local/bin/trash-empty
Default editor
To use an alternate default editor, define the EDITOR
environment variable in a shell initialization script as described in Environment variables.
As a regular user, su
will need to be used instead of sudo
for the environment variable to be pulled correctly:
$ su -c "crontab -e"
To have an alias to this printf
is required to carry the arbitrary string because su
launches in a new shell:
alias scron="su -c $(printf "%q " "crontab -e")"
run-parts issue
cronie uses run-parts
to carry out script in cron.daily
/cron.weekly
/cron.monthly
. Be careful that the script name in these won't include a dot (.), e.g. backup.sh
, since run-parts
without options will ignore them (see: run-parts(8)).
Running X.org server-based applications
Cron does not run under the X.org server therefore it cannot know the environmental variable necessary to be able to start an X.org server application so they will have to be defined. One can use a program like xuserrunAUR[ссылка недействительна: сохранено в aur-mirror] to do it:
17 02 * ... /usr/bin/xuserrun /usr/bin/xclock
Or then can be defined manually (echo $DISPLAY
will give the current DISPLAY value):
17 02 * ... env DISPLAY=:0 /usr/bin/xclock
If done through say SSH, permission will need be given:
# xhost +si:localuser:$(whoami)
Asynchronous job processing
If you regularly turn off your computer but do not want to miss jobs, there are some solutions available (easiest to hardest):
Cronie
cronie comes with anacron included. The project homepage reads:
Cronie contains the standard UNIX daemon crond that runs specified programs at scheduled times and related tools. It is based on the original cron and has security and configuration enhancements like the ability to use pam and SELinux.
Dcron
Vanilla dcronAUR supports asynchronous job processing. Just put it with @hourly, @daily, @weekly or @monthly with a jobname, like this:
@hourly ID=greatest_ever_job echo This job is very useful.
Cronwhip
cronwhipAUR is a script to automatically run missed cron jobs; it works with the former default cron implementation, dcron. See also the forum thread.
Anacron
Anacron is a full replacement for dcron which processes jobs asynchronously.
It is provided by cronie. The configuration file is /etc/anacrontab
. Information on the format can be found in the anacrontab(5)
man page. Running anacron -T
will test /etc/anacrontab
for validity.
Fcron
Like anacron, fcron assumes the computer is not always running and, unlike anacron, it can schedule events at intervals shorter than a single day which may be useful for systems which suspend/hibernate regularly (such as a laptop). Like cronwhip, fcron can run jobs that should have been run during the computer's downtime.
When replacing cronie with fcron be aware the spool directory is /var/spool/fcron
and the fcrontab
command is used instead of crontab to edit the user crontabs. These crontabs are stored in a binary format with the text version next to them as foo.orig in the spool directory. Any scripts which manually edit user crontabs may need to be adjusted due to this difference in behavior.
A quick scriptlet which may aide in converting traditional user crontabs to fcron format:
cd /var/spool/cron && ( for ctab in *; do fcrontab ${ctab} -u ${ctab} done )
See also the forum thread.
Ensuring exclusivity
If you run potentially long-running jobs (e.g., a backup might all of a sudden run for a long time, because of many changes or a particular slow network connection), then flock
(util-linux) can ensure that the cron job won't start a second time.
5,35 * * * * /usr/bin/flock -n /tmp/lock.backup /root/make-backup.sh
cronie
Long time users of vixie-cron (traditional cron) will be confused by how cronie is set up. Here is the relevant file hierarchy:
/etc |----- anacrontab |----- cron.d | ----- 0hourly |----- cron.daily |----- cron.deny |----- cron.hourly |----- cron.monthly |----- cron.weekly |----- crontab
Note that the crontab file is not created by default, but jobs added here will be run if you wish to use this file. Cronie provides both cron and anacron functionality. The difference is that cron will run jobs at particular time intervals (down to a granularity of one minute) if the machine is on at the particular time specified, while anacron runs jobs (with a minimum daily granularity) without assuming that the machine is turned on all the time. When the machine is on, anacron will check to see if there are any jobs that should have been run and will run them accordingly. The /etc/cron.d
and /etc/cron.hourly
directories are associated with cron functionality, while the /etc/anacrontab
file and /etc/cron.daily
, /etc/cron.weekly
, and /etc/cron.monthly
directories are associated with anacron functionality. The /etc/cron.deny
file is there so that any user who is not specifically prohibited can create their own cron jobs.
To implement a system-wide cron job, create a crontab-like file for it and place it in the /etc/cron.d
directory or add the job to /etc/crontab. Any executable (these are almost always shell scripts) in
/etc/cron.hourly
will be run every hour.
Anacron functionality is implemented similarly, however using the /etc/cron.daily
, /etc/cron.weekly
, or /etc/cron.monthly
directories, depending on how frequently you want the job to be run. The anacron job files are also executables; i.e. not in crontab-format. Anacron is triggered at the beginning of every hour by the crontab file /etc/cron.d/0hourly
which runs the executables in /etc/cron.hourly
including the file /etc/cron.hourly/0anacron
- deleting these will prevent anacron running any daily, weekly or monthly tasks.
systemctl status cronie
might show a message such as crond[<PID>]: (root) CAN'T OPEN (/etc/crontab): No such file or directory
. However, this is not an error as of cronie 1.4.8. See this discussion.Dcron
The cron daemon parses a configuration file known as crontab
. Each user on the system can maintain a separate crontab file to schedule commands individually. The root user's crontab is used to schedule system-wide tasks (though users may opt to use /etc/crontab
or the /etc/cron.d
directory, depending on which cron implementation they choose).
/var/spool/cron/root
# Run command at a scheduled time # Edit this 'crontab -e' for error checking, man 1 crontab for acceptable format # <@freq> <tags and command> @hourly ID=sys-hourly /usr/sbin/run-cron /etc/cron.hourly @daily ID=sys-daily /usr/sbin/run-cron /etc/cron.daily @weekly ID=sys-weekly /usr/sbin/run-cron /etc/cron.weekly @monthly ID=sys-monthly /usr/sbin/run-cron /etc/cron.monthly # mm hh DD MM W /path/command (or tags) # W = week: 0-6, Sun=0 21 01 * * * /usr/bin/systemctl suspend
These lines exemplify one of the formats that crontab entries can have, namely whitespace-separated fields specifying:
- @period
- ID=jobname (this tag is specific to dcron)
- command
The other standard format for crontab entries is:
- minute
- hour
- day
- month
- day of week
- command
The crontab files themselves are usually stored as /var/spool/cron/username
. For example, root's crontab is found at /var/spool/cron/root
See the crontab man page for further information and configuration examples.