Linux следить изменения файла

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Новый cron

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

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

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

Читайте также:  Как форматировать установочную флешку linux

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

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

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

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

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

Итоги

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

Источник

Мониторинг за изменениями файловой системы

В поисках готового велосипеда для решения задачи мониторинга за изменениями в ФС с поддержкой linux+freebsd наткнулся на приятную python либу watchdog (github, packages.python.org). Которая помимо интересных мне ОС поддерживает также MacOS (есть своя специфика) и Windows.
Тем, кому данный вопрос интересен и кого не отпугнет индийское происхождение автора, прошу .

Установка

Можно взять готовую версию из PIP:
$ pip install watchdog
Сам PIP ставится как пакет python-pip, порт devel/py-pip, etc.
Либо собрать из исходников через setup.py.

Достаточно подробно все расписано в оригинальном руководстве. Правда там описание версии 0.5.4, а сейчас актуальна 0.6.0. Однако, вся разница в правке копирайтов и замене отступа в 4 пробела на отступ в 2. «Google code style» 🙂

Вообще, там довольно много особенностей сборки по версиям самого python так и по целевой платформе. Они все описаны по ссылке выше, но если будет нужно, допишу в статью вкратце на русском.

Кроме того, собрать модуль можно на несовместимой ОС, но тогда в дело вступится fallback-реализация, делающая «слепки» структуры ФС с последующими сравнениями. Возможно, так кто-то и делал у себя при решении подобной задачи 🙂

Сам же я пробовал собрать под ubuntu 11.4 и freebsd-8.2 RELEASE, каких-либо проблем при сборке и работе не возникло.

Базовый пример

Предположим, что нас интересуют изменения по некоему пути /path/to/smth, связанные с созданием, удалением и переименованием файлов и директорий.

Класс Observer выбирается в /observers/__init__.py исходя из возможностей вашей ОС, так что нет необходимости самостоятельно решать, что же выбрать.
Класс FileSystemEventHandler является базовым классом обработчика событий изменения. Он мало что умеет, но мы научим его потомка:

Полный список методов можно увидеть в самом FileSystemEventHandler.dispatch: on_modified, on_moved, on_created, on_deleted.

Запускаем это все:

Observer является относительно далеким потомком threading.Thread, соотвественно после вызова start() мы получаем фоновый поток, следящий за изменениями. Так что если скрипт сразу завершится, то ничего толкового мы не получим. Реалиация ожидания зависит в первую очередь от применения модуля в реальном проекте, сейчас же можно просто сделать костыль:

Ждем событий изменений ФС до прихода Ctrl+C (SIGINT), после чего говорим нашему потоку завершиться и ждем, пока он это выполнит.

Запускаем скрипт, идем по нашему пути и:

На выходе скрипта имеем:

В методы нашего класса Handler в поле event приходят потомки FileSystemEvent, перечисленные в watchdog/events.py.
У всех есть свойства src_path, is_directory, event_type («created», «deleted», и т.п.). Для события moved добавляется свойство dest_path.

Ну если вы больше ничего не хотите… А разве ещё что-нибудь есть?

PatternMatchingEventHandler можно использовать для получения событий только о тех узлах ФС, имена которых подходят по маске с правилами:

  • * любые символы
  • ? любой единичный символ
  • [seq] любой единичный символ из указанных
  • [!seq] любой единичный символ НЕ из указанных

Задание правил выполняется при создании:

RegexMatchingEventHandler делает тоже самое, но с явным указанием regexp-выражений в конструкторе:

PatternMatchingEventHandler внутри себя в итоге транслирует шаблоны в регулярки, так что должен работать медленнее из-за наличия такого оверхеда.

Наконец, LoggingEventHandler выводит все в лог через logging.info().

— Вот и все. Может кому пригодится.

P.S.
При слежении за директорией, в которой (и в ее дочерних) содержатся папки/файлы не с ascii именованием, возникнет исключение exceptions.UnicodeEncodeError в глубинах watchdog’а. В Linux (inotify) он возникает в watchdog.observers.inotify.Inotify._add_watch.
Причина — чтение содержимого в ascii кодировке.
Для исправления ситуации можно пропатчить метод:

Вот пример исходной строки, и ее repr() до и после обработки encode():

Источник

MNorin.com

Блог про Linux, Bash и другие информационные технологии

Inotify в bash: ловим изменения файловой системы

Inotify — это подсистема ядра Linux, которая позволяет отслеживать изменения файловых систем. Использование этой подсистемы позволяет выполнять определенные действия в том случае если вы создали файл, что-то в него записали, открыли, закрыли, удалили и так далее. Использование этого механизма позволяет избавиться от необходимости вставлять в скрипты проверки с таймаутами при помощи команды sleep. Это упрощает логику скрипта, поскольку нам нужно просто ждать информацию об изменениях файловой системы, а при получении информации о том, что что-то изменилось, выполнить необходимые действия. Давайте рассмотрим пример скрипта, использующего inotify.

Читайте также:  Как запустить venv windows

Программы inotifywait и inotifywatch

Эти программы как раз и помогут нам обеспечить необходимый функционал отслеживания изменений файловой системы. В Debian и Ubuntu они входят в пакет inotify-tools. Установка пакета:

Как работает inotifywatch

Программа inotifywatch собирает статистику доступа к файловой системе при помощи inotify. По окончании работы программа выводит статистическую информацию в виде таблицы, включающей информацию об общем количестве событий, о количестве событий каждого типа и файле, для которого произошло событие. У неё есть ряд параметров, которые можно использовать для изменения параметров работы программы.

-h, —help Вывод информации по использованию
-v, —verbose Выводить дополнительную информацию на стандартный поток ошибок во время работы
-r, —recursive Отслеживать изменения рекурсивно для директории, переданной в качестве аргумента командной строки. Если внутри отслеживаемой директории будут созданы поддиректории во время работы программы, они автоматически будут отслеживаться. Если для отслеживания выбрана корневая директория или директория с большим количеством поддиректорий и файлов, установка отслеживания всех элементов файловой системы может занять некоторое время, в течение которого события получены не будут. Кроме того, возможно достижение максимального количества объектов файловой системы, разрешенных для отслеживания каждому пользователю. Значение по умолчанию 8192, и оно может быть увеличено записью нового значения в /proc/sys/fs/inotify/max_user_watches:

echo «51200» > /proc/sys/fs/inotify/max_user_watches

—exclude Исключить из отслеживания файлы с именами, совпадающими с шаблоном. Для шаблона используются расширенные регулярные выражения POSIX. Регистр при использовании данного параметра учитывается.
—excludei Исключить из отслеживания файлы с именами, совпадающими с шаблоном. Для шаблона используются расширенные регулярные выражения POSIX. Регистр при использовании данного параметра игнорируется.
@ Во время рекурсивного слежения за директорией исключить указанный файл из отслеживания. Если для файла указаны одновременно включение в список для отслеживания и исключение из отслеживания, он будет отслеживаться. Для файла можно использовать как относительный путь, так и абсолютный. Если имя файла включает символ «@», используйте абсолютный путь.
—fromfile Читать список файлов, которые будут отслеживаться и игнорироваться, из файла, каждое имя файла должно начинаться с новой строки. Если имя файла начинается с символа «@», отслеживание для него будет отключено. Если в качестве имени файла указать символ «-» (минус), то список файлов будет считываться со стандартного потока ввода. Этот параметр имеет смысл использовать, когда нужно отслеживать большое количество файлов, и их список неудобно передавать как аргументы командной строки.
-z, —zero Выводить колонки и строки таблицы даже в том случае, когда они пусты. По умолчанию пустые строки и колонки не выводятся.
-t ,
—timeout
Работать только в течение указанного количества секунд. Если этот параметр не указан, программа будет работать до получения сигнала на прерывание работы, например, по нажатию клавиш Ctrl+C
-e ,
—event
Отслеживать только события указанных типов. Этот параметр может быть указан более одного раза. Если он не указан, будут отслеживаться события всех типов
-a ,
—ascending
Сортировать вывод по возрастанию количества событий для указанного типа событий. Типы событий, по которым можно осуществлять сортировку, включают «total» и события, которые перечислены ниже, за исключением «move» и «close» (вместо них нужно указывать «moved_to», «moved_from», «close_write» и «close_nowrite»). По умолчанию сортировка производится по убыванию по полю «total».
-d ,
—descending
Сортировать вывод по уменьшению количества событий для указанного типа событий. Типы событий, по которым можно осуществлять сортировку, включают «total» и события, которые перечислены ниже, за исключением «move» и «close» (вместо них нужно указывать «moved_to», «moved_from», «close_write» и «close_nowrite»). По умолчанию сортировка производится по убыванию по полю «total».

Типы событий для отслеживания:

access Отслеживаемый файл или файл в отслеживаемой директории был прочитан
modify Отслеживаемый файл или файл в отслеживаемой директории был записан
attrib Метаданные отслеживаемого файла или файла в отслеживаемой директории были изменены. Сюда включаются изменения времени доступа и изменения, права доступа, расширенные атрибуты и так далее.
close_write Отслеживаемый файл или файл в отслеживаемой директории был закрыт после открытия его в режиме записи. Это не говорит о том, что в файл были записаны какие-то данные.
close_nowrite Отслеживаемый файл или файл в отслеживаемой директории был закрыт после открытия в режиме только для чтения
close Отслеживаемый файл или файл в отслеживаемой директории был закрыт, при этом неважно, в каком режиме он был открыт. Имейте в виду, что это событие рализовано просто прослушиванием обоих событий close_write и close_nowrite, поэтому все события будут выведены именно как одно из них, а не как CLOSE. Этот тип скорее как сокращение для двух других типов событий
open Отслеживаемый файл или файл в отслежваемой директории был открыт
moved_to Файл или директория были перемещены в отслеживаемую директорию. Это событие возникает даже в том случае, когда файл был перемещен в пределах одной и той же директории
moved_from Файл или директория были перемещены из отслеживаемой директории. Это событие возникает даже в том случае, когда файл был перемещен в пределах одной и той же директории
move Файл или директория были перемещены из отслеживаемой директории или в неё. Это событие реализовано аналогично событию CLOSE, то есть, скорее как псевдоним для двух типов событий, moved_to и moved_from,поэтому все события будут выведены именно как одно из них, а не как MOVE
move_self Отслеживаемый файл или директорию были перемещены. После возникновения этого события файл или директория больше не отслеживается.
create Файл или директория были созданы в отслеживаемой директории
delete Файл или директория были удалены из отслеживаемой директории
delete_self Отслеживаемый файл или директория были удалены. После этого события файл или директория больше не отслеживается. Обратите внимание, что это событие может произойти, даже если оно явно не слушалось.
unmount Файловая система, накоторой находится отслеживаемый файл или директория, была отмонтирована. Поле возникновения этого события файл или директория перестает отслеживаться.Обратите внимание, что это событие может произойти, даже если оно явно не слушалось.

Пример работы программы inotifywatch:

Как работает inotifywait

Программа inotifywait работает несколько иначе. Она ждет возникновения события и выводит информацию об этом событии сразу, не дожидаясь сигнала прерывания.

Параметры inotifywait очень похожи на параметры inotifywatch:

-h, —help Вывод информации по использованию
-r, —recursive Отслеживать изменения рекурсивно для директории, переданной в качестве аргумента командной строки. Если внутри отслеживаемой директории будут созданы поддиректории во время работы программы, они автоматически будут отслеживаться. Если для отслеживания выбрана корневая директория или директория с большим количеством поддиректорий и файлов, установка отслеживания всех элементов файловой системы может занять некоторое время, в течение которого события получены не будут. Кроме того, возможно достижение максимального количества объектов файловой системы, разрешенных для отслеживания каждому пользователю. Значение по умолчанию 8192, и оно может быть увеличено записью нового значения в /proc/sys/fs/inotify/max_user_watches:

echo «51200» > /proc/sys/fs/inotify/max_user_watches

—exclude Исключить из отслеживания файлы с именами, совпадающими с шаблоном. Для шаблона используются расширенные регулярные выражения POSIX. Регистр при использовании данного параметра учитывается.
—excludei Исключить из отслеживания файлы с именами, совпадающими с шаблоном. Для шаблона используются расширенные регулярные выражения POSIX. Регистр при использовании данного параметра игнорируется.
@ Во время рекурсивного слежения за директорией исключить указанный файл из отслеживания. Если для файла указаны одновременно включение в список для отслеживания и исключение из отслеживания, он будет отслеживаться. Для файла можно использовать как относительный путь, так и абсолютный. Если имя файла включает символ «@», используйте абсолютный путь.
—fromfile Читать список файлов, которые будут отслеживаться и игнорироваться, из файла, каждое имя файла должно начинаться с новой строки. Если имя файла начинается с символа «@», отслеживание для него будет отключено. Если в качестве имени файла указать символ «-» (минус), то список файлов будет считываться со стандартного потока ввода. Этот параметр имеет смысл использовать, когда нужно отслеживать большое количество файлов, и их список неудобно передавать как аргументы командной строки.
-t ,
—timeout
Работать только в течение указанного количества секунд. Если этот параметр не указан, программа будет работать до получения сигнала на прерывание работы, например, по нажатию клавиш Ctrl+C
-e ,
—event
Отслеживать только события указанных типов. Этот параметр может быть указан более одного раза. Если он не указан, будут отслеживаться события всех типов
-m, —monitor Выполняться постоянно. По умолчанию программа завершает свою работу после появления первого события
-o, —output Выводить события в файл вместо стандартного потока вывода
-s, —syslog Выводить ошибки в системный модуль syslog вместо вывода в стандартный поток ошибок
-d, —daemon То же самое, что и —monitor, но запись событий производится в файл, указанный в параметре —output. Вывод ошибок производится так же, как при использовании параметра —syslog
-q, —quiet Если этот параметр указан один раз, программа будет выводить меньше информации. В частности, не будет выводиться сообщение о том, что все соединения для отслеживания установлены.

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

-c, —csv Вывод в формате CSV (comma-separated values). Такой формат вывода удобно использовать в тех случаях, когда имена файлов могут содержать пробелы, потому что в таком случае разбивать информацию на поля по пробелам небезопасно.
—format Вывод в формате, определенном пользователем, с использованием синтаксиса, похожего на тот, который использует printf. Длина строки вывода информации о событии ограничена примерно 4000 символов и строки будут укорочены до этой длины. Поддерживаются следующие шаблоны:
1) %w — Этот шаблон будет заменен именем отслеживаемого файла, для которого произошло событие
2) %f — Когда событие возникает при отслеживании директории, этот шаблон будет заменен именем файла, для которого произошло событие. В противном случае он будет заменен пустой строкой.
3) %e — Этот шаблон заменяется событием или событиями, разделенными запятыми, которые произошли.
4) %Xe — Заменяется событиями, которые возникли, разделенными символом, который в данном шаблоне будет стоять на месте «X».
5) %T — Заменяется текущим временем в формате, определенным параметром —timefmt, который должен быть задан в видее, подходящем для передачи функции strftime.
—timefmt Установить формат вывода даты и времени в виде, подходящем для передачи функции strftime для использования совместно с шаблоном «%T» параметра «—format». Более подробно формат строки шаблона даты и времени можно посмотреть командой «man 3 strftime»

События, которые отслеживаются, точно такие же, как для программы inotifywatch.

Пример работы программы inotifywait:

Пишем скрипт, который использует inotify

Прежде всего определимся с условиями задачи, которую нам предстоит решить. Есть некоторые директории, куда пользователи загружают файлы (пусть это будут домашние директории пользователей, /home/ИМЯ-ПОЛЬЗОВАТЕЛЯ). Иногда пользователи эти файлы удаляют, поэтому нам нужно отслеживать изменения и при появлении новых файлов (или новых версий уже существующих файлов) копировать их в директорию /backup/ИМЯ-ПОЛЬЗОВАТЕЛЯ.

Для реализации нам нужно отслеживать изменения файловой системы, на которой находится директория /home, определять, что произошло событие закрытия файла после записи в него, получать директорию, в которой произошло закрытие файла, имя самого файла, определять имя директории, в которую планируется копировать файл, создавать её, если она еще не существует, и, собственно, копировать этот файл в эту директорию.

Как видите, всё достаточно просто. Если необходимо работать с файлами, имена которых содержат пробелы, вы можете использовать параметр «—csv» и разделять поля по запятой, а не по пробелу, как в примере, или добавить какой-то другой символ в строку шаблона вывода. Основной принцип работы при этом не изменится.

Источник

Читайте также:  Perfdiag logger 0xc0000035 windows 10
Оцените статью