[Перевод] Кунг-фу стиля Linux: наблюдение за файловой системой

Пользователи UNIX-подобных ОС, чтобы достичь желаемого результата, привыкли организовывать совместную работу различных программ, рассчитанных на решение какой-то одной задачи. Эти команды, например, помещают в файл Bash-скрипта, а потом, по своей инициативе, вызывают этот скрипт из командной строки. А что если нужно, чтобы система сама реагировала бы на какие-то изменения, действуя без вмешательства пользователя? Например, нужно организовать наблюдение за директорией и автоматически вызывать какую-то программу тогда, когда в эту директорию будет скопирован файл с использованием FTP. При этом не хотелось бы сидеть за компьютером во время передачи этого файла и ждать завершения операции.

92wtfq1l5itg70r0xo6lcpmoc04.jpeg
Самый простой, но не очень-то красивый способ это сделать заключается в периодическом сканировании директории. Вот весьма примитивный скрипт, который реализует такой функционал:

#!/bin/bash
while true
 do
   for I in `ls`
    do cat $I; rm $I
   done
 sleep 10
done


В этом примере я вывожу содержимое файла в консоль и удаляю его. Но в реальной жизни с подобным файлом можно сделать что-нибудь куда более интересное. Это — пример того, как не стоит писать скрипты. Ведь скрипт всё время выполняется. К тому же, такое решение задачи нельзя назвать красивым или остроумным. (Если вы полагаете, что в данном примере мне стоило бы использовать конструкцию for I in * — попробуйте это сделать в пустой директории и вы поймёте причину использования команды ls.)

Как организовать наблюдение за файловой системой в Linux?

Более симпатичное решение задачи


Если говорить честно, то для решения нашей задачи хорошо было бы сделать нечто, выглядящее лучше вышеприведённого примера. В современных ядрах (начиная с 2.6.13) есть механизм уведомлений о событиях файловой системы, представленный интерфейсом inotify. Соответствующие вызовы можно использовать программно, применяя заголовочный файл sys/inotify.h. Существует и набор инструментов командной строки, который можно установить, обычно представленный пакетом inotify-tools.

Один из инструментов этого пакета, inotifywait, позволяет улучшить код нашего примера. Скажем, переделать код можно так:

#!/bin/bash
while true
 do
   if FN=`inotifywait –e close_write,moved_to --format %f .`
   then
    cat $FN
    rm $FN
   fi
 done


Я думаю, что этот вариант лучше предыдущего. Скрипт вызывается не через заданные промежутки времени, а только тогда, когда в файловой системе что-то произошло. Я полагаю, что любая нормальная программа, воздействующая на файлы, находящиеся в директории, либо открывает файлы для записи и закрывает их после завершения операции, либо перемещает файлы в директорию. Наша программа отреагирует на оба эти события, а благодаря %f команда сообщит имя файла. Есть, конечно, и другие события, за которыми можно наблюдать.

Если вас интересует вопрос о том, почему необходимо наблюдать за событием перемещения файла, подумайте о том, как работает большинство текстовых редакторов и программ для загрузки файлов по сети. Обычно новому файлу не дают постоянного имени до тех пор, пока не завершится его обработка. Например, Chrome будет загружать файл с именем test.txt, дав ему временное имя test.txt.crdownload (или имя, подобное этому). Файл будет переименован (перемещён) в файл test.txt только после завершения загрузки.

Если вы хотите попробовать команду inotifywait без написания скрипта, чтобы своими глазами увидеть то, как она работает, откройте пару окон терминала и воспроизведите в этих окнах то, что показано ниже.

6caad26c2fba78e229b17852c4b62a01.png


Исследование команды inotifywait

В окне, расположенном на заднем плане, выполните команду inotifywait. Не забудьте о точке в конце команды, которая указывает на то, что наблюдать надо за файлами в текущей директории. Затем, в другом окне терминала, создайте в той же самой директории файл. В окне первого терминала будет выведено имя файла, после чего inotifywait завершит работу. В скрипте используется тот же самый механизм, с его помощью скрипт записывает имя файла в переменную FN, выполняет некие действия и перезапускает inotifywait. Кстати, можно сделать так, чтобы утилита inotifywait, после срабатывания, не завершала бы работу, но это усложнит скрипт. Это, правда, устранит проблему, которая может возникнуть в том случае, если имя файла меняется в ходе попытки его обработать средствами скрипта.

Ещё один инструмент для наблюдения за файловой системой, inotifywatch, тоже реагирует на изменения файлов, но он осуществляет мониторинг файловой системы в течение некоторого времени, а потом выдаёт сводку по зафиксированным изменениям. Если вы полагаете, что это именно то, что вам нужно, почитайте справку по inotifywatch.

Новый cron


Хотя мы и улучшили наш скрипт, он всё ещё далёк от идеала. Вполне возможно то, что нужно организовать наблюдение за множеством директорий. Вряд ли кому-то захочется воспроизводить вышеописанную последовательность действий в применении к каждой интересующей его директории.

Для решения нашей задачи можно воспользоваться и ещё одной программой, называемой incron (я почти уверен в том, что вам эта программа пригодится, и что её стоит установить). Эта утилита похожа на cron, но вместо того, чтобы выполнять какие-то действия, ориентируясь на события, связанные с временем, она ориентируется на события, связанные с файлами. После её установки вам, вероятно, если вы планируете ей пользоваться, стоит отредактировать файлы /etc/incron.allow и /etc/incron.deny. Особенно — если вы будете применять её, работая как обычный пользователь.

Предположим, нам надо выполнять некий скрипт в том случае, если в директории hexfiles появится какой-нибудь файл. Для редактирования таблицы событий, за которыми наблюдает incron, можно воспользоваться командой incrontab -e. Данные, вносимые в эту таблицу, представляют собой описания задач и по-особенному форматируются. В частности, тут для разделения столбцов используются не знаки табуляции, а пробелы. Вот строка, которая позволяет решить вышеописанную задачу:

/home/alw/Downloads/hexfiles IN_CLOSE_WRITE,IN_MOVED_TO /home/alw/bin/program_cpu $@/$#


Конструкция $@/$# в конце этой строки позволяет получить полный путь к файлу, на событие, произошедшее с которым, отреагировала программа. Тут, кроме того, можно получить время возникновения события — либо в виде текста ($%), либо в виде числа ($&). С помощью incron можно наблюдать за обычными событиями. Утилита, кроме того, поддерживает различные опции. Например, можно не разыменовывать символические ссылки. Подробности об incron ищите в справке к утилите.

Настройка incron с использованием графического интерфейса


Я — не большой любитель Linux-инструментов с графическим интерфейсом, но я знаю, что многим они нравятся. Если вы — из их числа — вот incrontab-редактор, написанный на Java. Нельзя сказать, что этот проект отличается подробной документацией, но его использование упрощает то, что в него можно импортировать файл incrontab. Если он у вас есть — ищите его по пути /var/spool/incron/your_user_id. Если посмотреть на окно редактора, показанное ниже, можно заметить, что он позволяет упростить создание incron-таблицы.

f0a8a333f178805edb2a8c6559bb8d64.png


Графический интерфейс для incron

Обычно системные файлы можно найти в /etc/incron.d. Пути расположения файлов можно задавать в файле /etc/incron.conf. Поэтому, если вам нужно поменять место расположения файла таблицы, но вы не знаете о том, где его искать, загляните в этот файл.

Итоги


Использование incron выглядит как очень аккуратное решение задачи мониторинга файловой системы. Системная программа берёт на себя заботу о наблюдении за событиями файловой системы, а скрипт запускается лишь тогда, когда это нужно. Кроме того, используя эту программу, можно легко узнать о том, за чем именно организовано наблюдение. В результате incron — это инструмент, с помощью которого можно сделать куда больше, чем наблюдение за текущей папкой в открытом окне терминала.

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

oug5kh6sjydt9llengsiebnp40w.png

3piw1j3wd_cgmzq9sefgferaumu.png

© Habrahabr.ru