Задания по расписанию: cron и systemd-таймеры
Как запускать задачи по расписанию, почему задание работает руками и молчит в cron, и когда стоит перейти на systemd-таймеры.
Обновлено 23 августа 2026 г.
Резервные копии, продление сертификатов, очистка временных файлов, ночные отчёты — всё это задачи по расписанию. В Linux их решают двумя способами: классическим cron и таймерами systemd.
Cron: быстрый старт
Расписание пользователя правится так:
crontab -e
crontab -l
Формат строки — пять полей и команда:
# мин час день месяц день-недели команда
0 4 * * * /usr/local/bin/backup.sh
*/15 * * * * /usr/local/bin/check.sh
30 3 * * 0 /usr/bin/systemctl restart myapp
Полезные сокращения: @daily, @hourly, @reboot. Проверить, что задания вообще запускались:
grep CRON /var/log/syslog | tail -30
journalctl -u cron --since "1 hour ago"
Почему скрипт работает руками, но не в cron
Это самая частая проблема, и причина почти всегда одна из трёх.
Другое окружение. У cron минимальный PATH и нет ваших переменных из .bashrc. Пишите полные пути к программам и задавайте переменные явно в начале скрипта или в crontab:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Другой каталог. Задание стартует в домашнем каталоге пользователя, относительные пути ведут не туда. Всегда используйте абсолютные пути.
Вывод уходит в никуда. Ошибка была, но её никто не увидел. Пишите журнал:
0 4 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
Ещё две мелочи: символ % в строке cron нужно экранировать как \%, а в файле crontab обязателен перевод строки в конце — иначе последнее задание игнорируется.
Проверять, что задание отработало, нужно снаружи. Молчащий cron выглядит точно так же, как успешный. Настройте push-проверку в Uptime Kuma: скрипт в конце дёргает адрес, и если сутки не дёргал — приходит тревога.
Таймеры systemd
Когда задача сложнее одной команды, таймер удобнее: у него есть журнал, зависимости, ограничения ресурсов и защита от одновременного запуска двух копий.
# /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
# /etc/systemd/system/backup.timer
[Unit]
Description=Run nightly backup
[Timer]
OnCalendar=*-*-* 04:00:00
Persistent=true
RandomizedDelaySec=15m
[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers
journalctl -u backup.service -n 50
Persistent=true догонит пропущенный запуск, если машина была выключена, — cron так не умеет. RandomizedDelaySec разносит нагрузку, чтобы десяток задач не стартовал в одну секунду.
Что стоит учесть
- Время на машине — UTC по умолчанию. Проверьте
timedatectlперед тем, как ставить «в 4 утра». - Тяжёлые задачи (архивы, проверка копий) упираются в диск. См. скорость диска и ставьте их на ночь.
- Долгая задача, запускаемая каждые пять минут, наложится сама на себя. В systemd поможет
Type=oneshot, в cron — блокировка черезflock:
*/5 * * * * /usr/bin/flock -n /tmp/job.lock /usr/local/bin/job.sh