Скрипт для мониторинга папки на наличие новых файлов?


127

Как обнаружить новые файлы в папке с помощью скрипта? Я хотел бы обработать файлы, как только они будут созданы в папке. Возможно ли это сделать или мне нужно запланировать скрипт с который проверяет наличие новых файлов каждую минуту или около того?


1
Собираетесь ли вы удалять файлы из папки после их обработки?
ztank1013

Ответы:


151

Вы должны рассмотреть возможность использования 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

В Ubuntu inotifywaitпредусмотрен inotify-toolsпакет. Начиная с версии 3.13 (текущей в Ubuntu 12.04) inotifywaitимя файла будет отсутствовать без опции -f. Старые версии, возможно, должны быть принуждены. Важно отметить, что эта -eопция inotifywaitявляется лучшим способом фильтрации событий. Кроме того, ваша readкоманда может назначить позиционный вывод нескольким переменным, которые вы можете использовать или игнорировать. Нет необходимости использовать grep / sed / awk для предварительной обработки вывода.


1
Большой! Это inotifywaitбыло именно то, что я хотел.
ihatetoregister

2
Просто хочу обновить это. Вам не нужен awk для достижения этой цели. Вы можете отфильтровать события с помощью '-e create' и получить только имя файла, выполнив '-f% f' или полный путь, используя '-f% w% f'. Таким образом, первая строка приведенного выше сценария выглядит так: inotifywait -m / path -f% w% f -e create |
Lugoues

2
@Lugoues, и теперь, когда вы пытаетесь использовать -f, вы получаете. The '--filename' option no longer exists. The option it enabled in earlier versions of inotifywait is now turned on by default.Так что вам нужно только сделать, inotifywait -m /path -e create |я собираюсь попытаться отредактировать этот ответ.
Бруно Броноски

1
Теперь есть еще и переносной инструмент для этого под названием fswatch. Я не писал это, но это с открытым исходным кодом, и я использую его.

1
@Wender inotfiywait выводит 3 фрагмента информации в одну строку при запуске. Встроенный bash 'read' читает строку ввода и присваивает каждой из трех частей информацию переменной. Таким образом, первый фрагмент назначается переменной path, второй - action, а третий - file. Присвоив значения этим переменным, они становятся доступными для последующего использования (как в строке эха). Дополнительная информация: tldp.org/LDP/Bash-Beginners-Guide/html/sect_08_02.html
Тим

26

Я предпочитаю incron, так как им легче управлять. По сути это сервис, который использует, inotifyи вы можете настроить конфигурации для выполнения действий, основанных на операциях изменения файлов.

Пример:

<directory> <file change mask> <command or action>  options
/var/www/html IN_CREATE /root/scripts/backup.sh

Вы можете увидеть полный пример здесь: http://www.cyberciti.biz/faq/linux-inotify-examples-to-replicate-directories/


24

Я только что подготовил это, и не вижу никаких больших проблем с этим, кроме крошечного шанса пропустить файлы между проверками.

while true
do
       touch  ./lastwatch
       sleep 10
       find /YOUR/WATCH/PATH -cnewer ./lastwatch -exec SOMECOMMAND {} \;
done

Если обработка вашего файла не занимает много времени, вы не должны пропустить ни одного нового файла. Вы также можете задокументировать действия ... Это не пуленепробиваемое, но оно служит некоторым целям без внешних инструментов, таких как inotify.


Хороший улов. Я немного улучшил его, чтобы поддерживать пробелы в именах файлов.
Майкл Сакки

Абсолютно. Это путь. Не совсем уверен, почему я пошел по этому пути, я обычно использую -exec.
Майкл Сакки

это не в реальном времени. в реальном времени всегда лучше
Фархан

3
Лучшее решение, если inotifyне доступно. Я бы добавил, -type fчтобы отфильтровывать только файлы. В противном случае папка также будет возвращена.
Сяо Пэн - ZenUML.com

Да - -f filenameвариант отличный. Тогда единственный оставшийся вопрос - как заставить это начаться после перезагрузки. Я собираюсь использовать это с моей солнечной установкой, os.system("ssh me@mysystem ' ( touch /home/me/alarms/low24 ) '")чтобы создание этого файла заставило главный компьютер использовать espeakи объявить о низком напряжении. Он уже отправляет мне электронное письмо, но так как моя система уже говорит о времени в верхней части часа, у нее есть все остальное. askubuntu.com/questions/977613/...
SDsolar

19

Вы можете использовать watchв своем скрипте

watch -n 0.1 ls <your_folder>

Мониторинг вашей папки и выводит список всего в ней каждые 0,1 секунды

недостаток

Не в режиме реального времени, поэтому, если файл был создан и удален менее чем за 0,1 секунды, то это не будет работать, watchподдерживает только минимум 0,1 секунды.


Это было именно то, что я пытался вспомнить! Большое спасибо!!
Жоабе Лусена

9

Я предполагаю, что целевая папка (я буду называть ее isemptyпросто для удобства) пуста, и вы ожидаете, чтобы один или несколько файлов были туда сброшены.

Вы можете использовать следующую команду:

ls -1A isempty | wc -l

просто чтобы проверить, пуста ли папка, на самом деле она вернет 0, если нового файла нет (следовательно, isemptyпапка еще пуста), или, с другой стороны, вернет значение больше 0 (на самом деле число файлов в данный момент в папке).

Тем не менее, глупый тест if / then может сделать всю работу:

if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi

Конечно, do_somethingфункция должна будет манипулировать файлом (ами) внутри isemptyпапки, а затем удалять его (их) из самой папки после обработки.

Добавление в ваш crontab строки, подобной следующей, будет запускать проверку раз в минуту и, do_somethingесли конечно, папка не пуста, будет запускаться действие:

* * * * *     if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi

Это решение работает для смонтированных удаленных файловых систем. Разработчик (-и) inotify-tools работает над предохранителем (или был в середине 2014 года).
Рондо

3
Вы никогда не должны использовать lsдля сценариев. findВместо этого используйте или просто добавьте
andsens

6

Если вы хотите обнаружить новые файлы, затем обработайте их и в конце удалите обработанные файлы, которые вы можете использовать systemd.path . Этот метод основан на inotify. Существует опция DirectoryNotEmpty, поэтому systemd может запускать ваш скрипт всегда, когда обнаруживает какие-либо файлы в каталоге. Вы должны помнить, что это будет работать, только если вы можете удалить исходные файлы и скрипт оставит каталог пустым.

Сначала подготовьте файл mymonitor.service

[Unit]
Description=Start the script

[Service]
Type=oneshot
ExecStart=/path/to/your/script

затем перейдите к mymonitor.path, чтобы определить путь

[Unit]
Description= Triggers the service

[Path]
DirectoryNotEmpty=/path/to/monitor

[Install]
WantedBy=multi-user.target

Если имя файла .path совпадает с именем службы, нет необходимости указывать имя службы в файле .path.

Основан на мониторинге доступа к файлам для чайников


4

entr

Использование entrэто новый способ сделать это (это кроссплатформенный). Примечание entrне использует опрос, что дает ему огромное преимущество над многими альтернативами.

Использует kqueue(2)или inotify(7)чтобы избежать опроса. entrбыло написано, чтобы сделать быструю обратную связь и автоматическое тестирование естественным и совершенно обычным.

На BSD он использует pledge(2)

Вы можете установить его с

apt-get install entr
dnf install entr

Вы можете отслеживать каталог для новых дополнений, используя

while $(true); do
  # echo ./my_watch_dir | entr -dnr echo "Running trigger..."
  echo ./my_watch_dir | entr -dnr ##MY COMMAND##
done;

Варианты объяснения (из документов),

  • -d Отслеживайте каталоги обычных файлов, предоставляемых в качестве входных данных, и выходите, если добавлен новый файл. Эта опция также позволяет явно указывать каталоги. Файлы с именами, начинающимися на «.» игнорируются
  • -nЗапустить в неинтерактивном режиме. В этом режиме entr не пытается читать из TTY или изменять его свойства.
  • -r Перезагрузите постоянный дочерний процесс. Как и в стандартном режиме работы, утилита, которая завершает свою работу, не выполняется снова, пока не будет обработано событие файловой системы или клавиатуры. SIGTERMиспользуется для прекращения работы утилиты до ее перезапуска. Группа процессов создается для предотвращения маскирования сигналов сценариями оболочки. entrожидает завершения работы утилиты, чтобы убедиться, что такие ресурсы, как сокеты, закрыты. Управление TTY не передается дочернему процессу.

2

Баш не может сделать это легко. Вам нужно было бы получить список всех файлов в папке, периодически получать новый список и сравнивать их, чтобы увидеть, что изменилось.

То, что вы ищете, называется inotify. Он встроен в ядро ​​Linux, и вы можете сидеть и ждать, пока что-то произойдет, и в этот момент inotify возвращается и говорит: «Привет, есть новый файл с именем foobar».

Чтобы выполнить то, что вы хотите, вам нужно переключиться на что-то вроде Perl и использовать Linux :: Inotify2 (python, вероятно, также поддерживает inotify, но я человек Perl).


0

Это работает в Cygwin и Linux. Некоторые из предыдущих решений, которые записывают файл, приводят к перегрузке диска. Этот скипетт не имеет этой проблемы:

SIG=1
SIG0=$SIG
while [ $SIG != 0 ] ; do
 while [ $SIG = $SIG0 ] ; do
   SIG=`ls -1 | md5sum | cut -c1-32`
   sleep 10
 done
 SIG0=$SIG
 ls -lrt | tail -n 1
done

0

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

Var_dir="${1:-/tmp}"
Var_diff_sleep="${2:-120}"
Var_diff_opts="--suppress-common-lines"
Func_parse_diff(){
    _added="$(grep -E '>' <<<"${@}")"
    if [ "${#_added}" != "0" ]; then
        mapfile -t _added_list <<<"${_added//> /}"
        _let _index=0
        until [ "${#_added_list[@]}" = "${_index}" ]; do
            _path_to_check="${Var_dir}/${_added_list[${_index}]}"
            if [ -f "${_path_to_check}" ]; then
                echo "# File: ${_path_to_check}"
            elif [ -d "${_path_to_check}" ]; then
                echo "# Directory: ${_path_to_check}"
            if [ -p "${_path_to_check}" ]; then
                echo "# Pipe: ${_path_to_check}"
            fi
            let _index++
        done
        unset _index
    fi
}
Func_watch_bulk_dir(){
    _current_listing=""
    while [ -d "${Var_dir}" ]; do
        _new_listing="$(ls "${Var_dir}")"
        _diff_listing="$(diff ${Var_dec_diff_opts} <(${Var_echo} "${_current_listing}") <(${Var_echo} "${_new_listing}"))"
        if [ "${_diff_listing}" != "0" ]; then
            Func_parse_diff "${_diff_listing}"
        fi
        _current_listing="${_new_listing}"
        sleep ${Var_diff_sleep}
    done
}

Вот ссылка на скрипт, который использует модифицированную версию выше для автоматической расшифровки файлов или каталогов, найденных в точке монтирования sshfs; вышеупомянутый проект.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.