Рутина администратора - это бэкапы по ночам, ротация логов, выгрузка отчётов, чистка временных файлов. Запускать это руками нельзя: забудешь, уйдёшь в отпуск, перепутаешь время. Задача урока - научиться отдавать повторяющиеся и разовые задачи планировщику, чтобы система делала их сама и в нужный момент. Разберём классику (cron, at, anacron) и современный механизм systemd timers, который в 2026 во многих дистрибутивах стал основным. Покрытие LPI: crontab, формат строки, /etc/crontab и cron.d, каталоги cron.{hourly,daily,weekly}, at/atq/atrm, права allow/deny и таймеры с OnCalendar.

Как это работает
Cron - это демон (crond или cron), который раз в минуту просыпается, читает таблицы заданий и сверяет текущее время с расписанием каждой строки. Совпало - порождает процесс и выполняет команду. Расписание задаётся пятью полями: минута, час, день месяца, месяц, день недели. У каждого пользователя своя таблица (пользовательский crontab), плюс есть системные таблицы, где добавляется шестое поле - имя пользователя, от которого запускать.
Источников заданий несколько, и их легко спутать. Пользовательские кронтабы лежат в спул-каталоге (например /var/spool/cron/crontabs в Debian или /var/spool/cron в RHEL) и редактируются только через команду crontab, а не блокнотом. Системные - это файл /etc/crontab и отдельные файлы в /etc/cron.d. А каталоги /etc/cron.hourly, cron.daily, cron.weekly, cron.monthly - это просто папки со скриптами, которые запускает по очереди run-parts. То есть туда кладёшь исполняемый скрипт без всякого расписания, а сам момент запуска определяет система.
Тут вступает anacron. Обычный cron исходит из того, что машина работает круглосуточно: если в 3 ночи ноутбук был выключен, ночная задача просто пропадает. Anacron смотрит не на точное время, а на то, сколько дней прошло с последнего успешного запуска. Если daily-задача не выполнялась больше суток, anacron догонит её при ближайшем включении. Поэтому на десктопах и ноутбуках периодику cron.daily/weekly/monthly обычно тянет именно anacron, а cron отвечает лишь за hourly и за то, что вы прописали явно.
At решает другую задачу - не повтор, а один запуск в будущем. Указываете время, демон atd выполнит команду один раз и забудет про неё. Удобно для отложенного ребута, разового прогрева кеша, напоминания.
Systemd timers - это современная альтернатива всему перечисленному. Таймер состоит из двух юнитов: файла .service с самой командой и файла .timer с расписанием. Преимущества по сравнению с cron: запуск идёт через systemd, поэтому есть полноценные логи в journald, зависимости, ограничения по ресурсам через cgroups, рандомизация старта (чтобы сотня машин не ударила по серверу одновременно) и встроенный аналог anacron - параметр Persistent, который догоняет пропущенные запуски. Поэтому ротацию логов, fstrim и обновление баз многие дистрибутивы уже перевели на таймеры.
Команды и примеры
Свой кронтаб правят через редактор, а не файлом напрямую:
Код: Выделить всё
crontab -e # редактировать свою таблицу
crontab -l # показать
crontab -r # удалить целиком (осторожно, без подтверждения)
crontab -u backup -e # править таблицу пользователя backup (нужен root)Код: Выделить всё
# м ч дм мес дн команда
30 2 * * * /usr/local/bin/backup.sh # каждый день в 02:30
*/15 * * * * /usr/local/bin/check.sh # каждые 15 минут
0 9 * * 1-5 mailx -s report me@ex.ru < /r # будни в 9:00
0 0 1 * * /usr/local/bin/monthly.sh # 1-го числа в полночьСистемный crontab отличается шестым полем - пользователем:
Код: Выделить всё
# /etc/cron.d/mybackup
SHELL=/bin/bash
PATH=/usr/bin:/bin
17 4 * * * root /usr/local/bin/nightly.shКод: Выделить всё
install -m 0755 myjob /etc/cron.daily/myjob
run-parts --test /etc/cron.daily # показать, что запуститсяКод: Выделить всё
at 23:00 # сегодня в 23:00
at now + 30 minutes
at 10am tomorrow
echo "systemctl reboot" | at 03:00 # передать через stdin
atq # очередь заданий
atrm 7 # удалить задание номер 7Код: Выделить всё
# Debian/Ubuntu
systemctl status cron apt install cron anacron at
# RHEL/Fedora
systemctl status crond dnf install cronie at
journalctl -u cron -u crond --since todayКод: Выделить всё
# backup.service
[Unit]
Description=Ночной бэкап
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
# backup.timer
[Unit]
Description=Запуск бэкапа ночью
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.targetКод: Выделить всё
systemctl daemon-reload
systemctl enable --now backup.timer
systemctl list-timers --all # ближайшие и прошедшие срабатывания
systemd-analyze calendar "Mon *-*-* 09:00:00" # проверить выражение OnCalendarЧастые грабли
- Минимальное окружение. Cron запускает задания почти без переменных, PATH куцый, нет вашего .bashrc. Команда, что работала в шелле, в кроне падает с command not found. Лечение: полные пути или PATH= в начале кронтаба.
- Знак процента. В строке cron символ % означает перевод строки и обрезает команду. В date +%Y его надо экранировать как \% либо вынести логику в скрипт.
- Редактирование спул-файла руками вместо crontab -e: cron может не перечитать его или потерять. Всегда через crontab.
- День месяца И день недели вместе дают ИЛИ, а не И. Хотели последнюю пятницу - получили сюрприз.
- Скрипт в cron.daily с точкой в имени (backup.sh) run-parts молча проигнорирует. Имя должно быть без расширения.
- Куда уходит вывод. Cron шлёт stdout/stderr письмом локальному пользователю; если MTA нет, вывод теряется. Перенаправляйте в файл: >> /var/log/job.log 2>&1.
- Забыли systemctl daemon-reload после правки юнита или enable вместо enable --now - таймер есть, но не активирован.
- Anacron не про минуты и часы: у него гранулярность в сутки. Для ежеминутных задач он не подходит.
- Создайте скрипт /usr/local/bin/hb.sh, который пишет дату и uptime в /var/log/hb.log (date >> ... 2>&1), сделайте его исполняемым.
- Через crontab -e добавьте запуск каждые 2 минуты, подождите и убедитесь по логу, что он отрабатывает.
- Намеренно сломайте задание: уберите полный путь к скрипту и посмотрите в journalctl, как cron ругается; верните путь.
- Поставьте через at разовую задачу на 5 минут вперёд (записать строку в лог), проверьте atq, затем удалите её через atrm.
- Перепишите ту же задачу на systemd timer: создайте hb.service (Type=oneshot) и hb.timer с OnCalendar=*:0/2, включите enable --now.
- Сравните: посмотрите systemctl list-timers и journalctl -u hb.service - оцените, насколько прозрачнее логи у таймера, чем у cron.
- Добавьте в /etc/cron.allow только своего пользователя и проверьте, что другой непривилегированный пользователь больше не может сделать crontab -e.
- Назовите все пять полей строки cron по порядку и поясните разницу между */10 и 0-50/10 в поле минут.
- Чем содержимое /etc/cron.d отличается от пользовательского crontab по формату строки?
- Зачем нужен anacron и почему обычный cron не годится для ноутбука, который ночью выключен?
- Из каких двух юнитов состоит systemd timer и за что отвечает параметр Persistent в секции [Timer]?
- Как настроены права, если существует /etc/cron.allow, но нет /etc/cron.deny? А если нет ни того, ни другого?
- Почему задание, работающее в интерактивном шелле, может упасть в cron, и как это диагностировать?