linux scripting

cron

Планировщик задач (демон) — автоматическое выполнение команд по расписанию

Описание

cron — системный демон, запускающий задачи по заданному расписанию. Название происходит от греческого «хронос» (время). Демон работает постоянно в фоновом режиме и каждую минуту проверяет таблицы расписания (crontab), запуская команды, время которых наступило. Впервые реализован в AT&T Unix в 1970-х, современная реализация — Vixie cron (Пол Викси, 1988), используемая в большинстве Linux-дистрибутивов.

Демон cron читает расписание из нескольких источников: пользовательские crontab-файлы (/var/spool/cron/crontabs/), системный /etc/crontab, и файлы в директориях /etc/cron.d/, /etc/cron.hourly/, /etc/cron.daily/, /etc/cron.weekly/, /etc/cron.monthly/. Системный crontab имеет дополнительное поле пользователя.

Как правило, администратор не взаимодействует с демоном cron напрямую — управление расписанием происходит через команду crontab. Прямые опции демона используются при его ручном запуске или в нестандартных конфигурациях. Для проверки состояния используй systemctl status cron (или crond на RHEL/CentOS).

Синтаксис и формат crontab

cron [-f] [-l] [-L LOGLEVEL] [-n] /usr/sbin/cron -f # запустить в foreground (systemd/supervisord)

Структура строки crontab

*минуты
0–59
*часы
0–23
*дни месяца
1–31
*месяцы
1–12
*дни недели
0–7 (0,7=вс)
# Пользовательский crontab MIN HOUR DOM MON DOW COMMAND # Системный /etc/crontab и /etc/cron.d/* MIN HOUR DOM MON DOW USER COMMAND # Специальные строки @reboot CMD # при каждом старте системы @hourly CMD # каждый час (0 * * * *) @daily CMD # ежедневно в полночь (0 0 * * *) @weekly CMD # еженедельно (0 0 * * 0) @monthly CMD # ежемесячно (0 0 1 * *) @yearly CMD # ежегодно (0 0 1 1 *)

Спецсимволы в полях расписания

Флаги демона cron

ФлагОписание
-fForeground mode: не уходить в фон (daemon). Используется при запуске через systemd или supervisord, где демон должен оставаться на переднем плане
-lВключить syslog-логирование каждой запущенной задачи (по умолчанию отключено в некоторых версиях)
-L LEVELУровень детализации лога: 0 — нет логов; 1 — логировать запущенные задания; 2 — логировать каждое чтение crontab; 4 — логировать каждый crontab-тест; 8 — логировать pid процессов
-nНе перезапускать задачи, которые не завершились до следующего запланированного времени (no fork for mail). Актуально для long-running задач
-iИгнорировать /etc/cron.deny и /etc/cron.allow — позволить всем пользователям использовать crontab
-sВключить поддержку SELinux контекстов при запуске заданий (если cron собран с поддержкой SELinux)
-m CMDИспользовать CMD вместо sendmail для отправки вывода заданий по email. Например: -m /usr/bin/mail
-MНе отправлять email — игнорировать вывод задания (useful для verbose cron jobs без email)
-x FLAGSОтладочные флаги (misc,io,load,pars,sch,proc,pnt,bit,ext,lst,detail). Только для разработки cron

Паттерны использования

Управление демоном cron

# Проверить статус (systemd-системы)
systemctl status cron        # Debian/Ubuntu
systemctl status crond       # RHEL/CentOS/Fedora

# Перезапустить после изменения конфига
systemctl restart cron

# Включить автозапуск при старте
systemctl enable cron

# Просмотр логов cron
journalctl -u cron -f
grep CRON /var/log/syslog | tail -20

Примеры расписания

# Каждые 5 минут
*/5 * * * *  /usr/bin/check.sh

# В 3:30 ночи каждый день
30 3 * * *   /usr/bin/backup.sh

# По рабочим дням в 9:00
0 9 * * 1-5  /usr/bin/report.sh

# 1-го числа каждого месяца
0 0 1 * *    /usr/bin/monthly.sh

# Каждый час с 8 до 20
0 8-20 * * * /usr/bin/poll.sh

# Пн, Ср, Пт в 12:00
0 12 * * 1,3,5 /usr/bin/sync.sh

Системный /etc/crontab

# /etc/crontab — требует поле USER
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin

# MIN HOUR DOM MON DOW USER  COMMAND
17 *    * * *   root  cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root  test -x /usr/sbin/anacron || run-parts /etc/cron.daily
47 6    * * 7   root  test -x /usr/sbin/anacron || run-parts /etc/cron.weekly
52 6    1 * *   root  test -x /usr/sbin/anacron || run-parts /etc/cron.monthly

Перенаправление вывода

# Подавить вывод полностью
*/5 * * * * /usr/bin/job.sh >/dev/null 2>&1

# Логировать только ошибки
*/5 * * * * /usr/bin/job.sh >>/var/log/job.log 2>&1

# Раздельные файлы для stdout и stderr
*/5 * * * * /usr/bin/job.sh \
  1>>/var/log/job.out \
  2>>/var/log/job.err

# MAILTO="" — отключить email для одной задачи
MAILTO=""
*/5 * * * * /usr/bin/silent-job.sh

Переменные окружения в crontab

# Переменные задаются в начале crontab
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=admin@example.com
HOME=/root

# Важно: cron не загружает ~/.bashrc или ~/.profile
# Всегда используй абсолютные пути к командам

0 2 * * * /usr/local/bin/python3 /opt/scripts/etl.py
0 3 * * * /usr/bin/pg_dump mydb > /backups/db_$(date +\%Y\%m\%d).sql

Скрипт в /etc/cron.d/

# /etc/cron.d/myapp — системный cron для приложения
# Файл должен принадлежать root и не быть исполняемым
# chmod 644 /etc/cron.d/myapp

SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin

# MIN HOUR DOM MON DOW USER  COMMAND
0  */4  * * *  www-data  /opt/myapp/manage.py clearsessions
30 1    * * *  www-data  /opt/myapp/manage.py dbbackup

Советы и предупреждения

Совет: cron не загружает профиль пользователя
Задачи cron выполняются в минимальном окружении — без ~/.bashrc, ~/.profile, ~/.bash_profile. Переменная PATH обычно равна /usr/bin:/bin. Всегда используй абсолютные пути к командам (/usr/bin/python3, а не просто python3) или задавай PATH в начале crontab-файла.
Совет: используй flock для предотвращения параллельного запуска
Если задача может выполняться дольше интервала запуска, используй flock для блокировки: */5 * * * * flock -n /tmp/job.lock /usr/bin/job.sh. Это предотвратит накопление параллельных процессов. Альтернатива — run-one.
Внимание: экранирование символа % в crontab
Символ % в crontab имеет специальное значение — он интерпретируется как перевод строки и начало stdin. Если команда содержит % (например, date +%Y-%m-%d), его необходимо экранировать обратным слешем: date +\%Y-\%m-\%d.
Внимание: cron и системное время
Cron использует локальное системное время сервера. При переходе на летнее/зимнее время задачи могут быть пропущены или запущены дважды. На серверах рекомендуется использовать UTC: timedatectl set-timezone UTC. Для более предсказуемого планирования рассмотри anacron (запускает пропущенные задачи) или systemd timers.