Как использовать inotifywait для просмотра каталога для создания файлов определенного расширения

21

Я видел этот ответ .

Вы должны рассмотреть возможность использования inotifywait, например:

inotifywait -m /path -e create -e moved_to |
    while read path action file; do
        echo "The file '$file' appeared in directory '$path' via '$action'"
        # do something with the file
    done

Мой вопрос заключается в том, что приведенный выше скрипт следит за каталогом для создания файлов любого типа, но как мне изменить inotifywaitкоманду, чтобы она сообщала только тогда, когда файл определенного типа / расширения создан (или перемещен в каталог) - например, он должен сообщить, когда любой .xmlфайл создан.

ЧТО Я ПОПЫТАЛ

Я выполнил inotifywait --helpкоманду и прочитал параметры командной строки. Он имеет --exclude <pattern>и --excludei <pattern>команды для ИСКЛЮЧЕНИЯ файлов определенных типов (с помощью regEx), но мне нужен способ ВКЛЮЧИТЬ только файлы определенного типа / расширения.

Застенчивый
источник
Кстати, использование pathвыше, вероятно, не лучшее имя переменной, если вы хотите поиграть с этим первым в оболочке. Если вы используете его, то вы не сможете использовать команды и все остальное, поскольку это в основном просто переопределило стандарт PATH. Поэтому я рекомендую использовать альтернативное имя var, например, fpathвместо. т.е. while read fpath action fileлюбая стандартная команда, обычно доступная из вашей оболочки, все равно будет.
Креститель Матус
это довольно смешно, что нет опции включения.
Эрандрос

Ответы:

17

Как я могу изменить команду inotifywait, чтобы сообщать только при создании файла определенного типа / расширения

Обратите внимание, что это непроверенный код, поскольку у меня нет доступа к нему inotifyпрямо сейчас. Но что-то похожее на это должно сработать:

inotifywait -m /path -e create -e moved_to |
    while read path action file; do
        if [[ "$file" =~ .*xml$ ]]; then # Does the file end with .xml?
            echo "xml file" # If so, do your thing here!
        fi
    done
maulinglawns
источник
2
Это работает, и я проверил это с inotifywait.
TheBetterJORT
1
Как вы управляете этим? Это однократная команда, или она должна выполняться в цикле или что-то в этом роде? Возможно, как часть incron(я надеюсь, что нет).
SDsolar
@ SDolar Это меняется. Для меня, я обычно работаю inotifyлибо с nohupили запустить его с помощью пользовательской Systemd службы. Чаще всего последний.
Maulinglawns
9

Используйте двойной минус:

inotifywait -m --exclude "[^j][^s]$" /path -e create -e moved_to |
    while read path action file; do
        echo "The file '$file' appeared in directory '$path' via '$action'"
    done

Это будет включать только файлы JavaScript

Йонас Эрендель
источник
1
Хорошо, мне нравится, что он смещает фильтрацию, inotifywaitа не генерирует огромный вывод для всех файлов и фильтрует впоследствии (как в другом ответе). Не пробовал, но думаю, что это будет работать немного быстрее.
TMG
Это именно то, что я искал. Как изменить --excludeвход для просмотра .extфайлов. Это выполняется только один раз или в цикле?
Курокирасама
Это демон, поэтому он будет работать до тех пор, пока он не выйдет из строя или не выключится :)
Jonas Earendel
Извините, пропустил первый вопрос. inotifywait -m --exclude "[^.][^e][^x][^t]$" /home/jonas/Skrivbord/test -e create -e moved_to | while read path action file; do echo "The file '$file' appeared in directory '$path' via '$action'" done Я уверен, что регулярное выражение может быть оптимизировано, но этот ребенок работает :)
Jonas Earendel
Thanxs !! Я попробую это !!
Курокирасама
3

Хотя двойной отрицательный подход предыдущего ответа является хорошей идеей, поскольку (как отметил TMG) ​​он действительно переносит работу по фильтрации inotifywait, но он не верен.

Например, если файл заканчивается, asон не будет совпадать, [^j][^s]$потому что последняя буква sне совпадает [^s], поэтому он не будет исключен.

В логических терминах, если Sэто утверждение:

"последнее письмо s"

и Jэто утверждение:

«предпоследнее письмо есть j»

тогда значение --excludeпараметра должно семантически приравняться not(J and S), что по законам де Моргана является not(J) or not(S).

Другая потенциальная проблема заключается в том zsh, что in , $pathявляется встроенной переменной, представляющей эквивалент массива $PATH, поэтому while read path ...строка полностью испортится $PATHи приведет к тому, что все станет неисполнимым из оболочки.

Поэтому правильный подход:

inotifywait -m --exclude "[^j].$|[^s]$" /path -e create -e moved_to |
    while read dir action file; do
        echo "The file '$file' appeared in directory '$dir' via '$action'"
    done

Обратите внимание на то, .что необходимо после того, [^j]чтобы убедиться, что сопоставление применяется в предпоследней позиции, а также что |символ (представляющий логическое ИЛИ, упомянутое выше) не должен быть экранирован здесь, потому что --excludeпринимает расширенные регулярные выражения POSIX.

Адам Спирс
источник