incron это «cron для файловой системы»: команды запускаются не по расписанию, а когда с файлом или каталогом что-то происходит. Файл создали, изменили, удалили или переместили, и incron сразу запускает нужный скрипт. Работает он на механизме ядра inotify, так что не нужно каждую минуту опрашивать каталог из cron.
Сразу о состоянии проекта: последний выпуск incron 0.5.12 вышел ещё в 2015 году, с тех пор в репозитории только редкие правки. Программа простая и стабильная, пакеты есть в Debian, Ubuntu, Arch и Fedora, но новых функций ждать не стоит. Для новых задач на systemd-системах стоит присмотреться к path-юнитам, о них ниже.
Где incron пригодится
- обработать файл сразу после загрузки в каталог: сконвертировать, сжать, переложить;
- получить уведомление, если кто-то поменял важный конфиг вроде nginx.conf;
- запустить бэкап или синхронизацию, когда в каталоге появились новые данные;
- простой триггер сборки на отдельном сервере, когда туда прилетел артефакт.
Установка
# Debian, Ubuntu sudo apt install incron sudo systemctl enable --now incron # Arch sudo pacman -S incron sudo systemctl enable --now incrond # Fedora (на RHEL, Alma и Rocky пакет в EPEL) sudo dnf install incron sudo systemctl enable --now incrond
В Debian и Ubuntu служба называется incron, в Fedora и Arch incrond. В Debian пакет есть во всех актуальных ветках, от Bookworm до Sid, в Arch в репозитории extra, в Fedora и EPEL 8, 9 и 10.
Кому можно пользоваться incrontab
Как и у cron, доступ задаётся двумя файлами, это описано в man incrond. Если есть /etc/incron.allow, пользоваться incron могут только те, кто в нём записан. Если его нет, но есть /etc/incron.deny, то все, кроме перечисленных. Если нет ни того ни другого, ограничений нет. Системные таблицы с правами root лежат в /etc/incron.d/, пользовательские редактируются командой incrontab и выполняются от имени владельца таблицы.
incrontab -e # редактировать свои правила incrontab -l # показать правила
Формат правил
Каждая строка выглядит так:
<путь> <маска событий> <команда>
Основные события: IN_CREATE, IN_MODIFY, IN_DELETE, IN_MOVED_TO, IN_MOVED_FROM, IN_ATTRIB, IN_CLOSE_WRITE. Несколько событий пишутся через запятую. Есть и сокращения: IN_ALL_EVENTS для всех событий, IN_MOVE для обоих перемещений, IN_CLOSE для закрытия файла. Один и тот же путь в таблице может встречаться только один раз, остальные строки с ним игнорируются.
В команде можно подставлять:
- $@ путь из правила;
- $# имя файла, с которым случилось событие;
- $% событие текстом, например IN_CLOSE_WRITE;
- $& событие числом;
- $$ сам знак доллара.
Ещё есть три собственные опции incron, их пишут в маске через запятую. loopable=true не реагирует на новые события, пока не закончилась команда от предыдущего. recursive=false следит только за самим каталогом, без подкаталогов: значит, по умолчанию эта версия incron следит и за подкаталогами. dotdirs=true включает в наблюдение скрытые каталоги, имя которых начинается с точки.
Примеры
Обработка загруженных файлов. Лучше ловить IN_CLOSE_WRITE, а не IN_CREATE: событие придёт, когда файл дописан, а не когда появился пустой файл.
/var/www/uploads IN_CLOSE_WRITE /usr/local/bin/process_new_file.sh $@/$#
Уведомление о правке конфига. Отправку в почту или мессенджер удобнее держать в отдельном скрипте, а не городить длинную команду прямо в таблице.
/etc/nginx/nginx.conf IN_MODIFY /usr/local/bin/notify_nginx_change.sh
Пример скрипта, который аккуратно берёт путь из аргумента:
#!/bin/bash # /usr/local/bin/process_new_file.sh f="$1" [ -f "$f" ] || exit 0 logger -t incron "новый файл: $f" # здесь обработка, например: # convert "$f" -resize 1600x "$f"
Скрипт должен спокойно переживать повторный запуск на том же файле: события иногда приходят дважды. А если скрипт сам пишет в каталог, за которым следит incron, без loopable=true легко получить бесконечный цикл.
Ограничения и частые ошибки
- Служба не запущена: пакет поставили, а
systemctl enable --nowне сделали. - Пользователь не попал в incron.allow, и incrontab ему отказывает.
- Повесили IN_CREATE и получили недописанный файл.
- Пробелы и спецсимволы в именах ломают команду: передавайте путь аргументом и берите его в кавычки уже в скрипте.
- Шумный каталог вроде всего /tmp даёт шторм событий. Следите за узким каталогом приложения.
- Кончились inotify-вотчи: на больших деревьях упирается в fs.inotify.max_user_watches.
- Логи ищите в
journalctl -u incron(или-u incrond) и в syslog.
sysctl fs.inotify.max_user_watches journalctl -u incron -n 50
Альтернатива: systemd.path
Если задача звучит как «появился файл, запусти сервис», на системе с systemd это делается без отдельного демона. Path-юнит следит за путями через PathExists, PathChanged, PathModified или DirectoryNotEmpty и запускает одноимённый сервис. Для аудита безопасности, кто и что поменял, правильнее auditd, а для задач по расписанию обычный cron или таймеры systemd.
# /etc/systemd/system/uploads.path [Path] DirectoryNotEmpty=/var/www/uploads [Install] WantedBy=multi-user.target # рядом uploads.service с ExecStart=/usr/local/bin/process_uploads.sh # sudo systemctl enable --now uploads.path
В итоге incron до сих пор хорошо закрывает нишу «файл изменился, сразу скрипт»: обработка загрузок, уведомления о правке конфигов, простая автоматизация. Ставьте пакет, включайте службу, ограничивайте доступ через incron.allow и пишите короткие скрипты, которые не боятся повторного запуска. А для новых задач на systemd-серверах сначала посмотрите на path-юниты.