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


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
Просто хочу оновити це. Для досягнення цього вам не потрібно ніяких проблем. ви можете відфільтрувати події за допомогою '-e create' та отримати лише ім'я файлу, виконавши '-f% f' або повний шлях, використовуючи '-f% w% f'. Отже, перший рядок вищезазначеного сценарію стає: inotifywait -m / path -f% w% f -e create |
Lugoues

2
@Lugoues, і тепер, коли ти намагаєшся використовувати -як ви отримаєте 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' зчитує рядок введення та присвоює кожну з трьох частин інформації змінній. Таким чином, перший фрагмент призначається шляху змінної, другий до дії, а другий - до файлу. Призначивши ці змінні значення, вони можуть бути використані пізніше (наприклад, у рядку ехо). Більше інформації: 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

Якщо обробка вашого файлу не займе багато часу, ви не повинні пропустити жоден новий файл. Ви також можете переглядати діяльність ... Це не куленепробивна, але вона виконує деякі цілі без зовнішніх інструментів, таких як ініціація.


Хороший улов. Я трохи покращив його, щоб підтримати пробіли у назви файлів.
Майкл Саккі

Абсолютно. Це шлях. Не дуже впевнений, чому я пішов цією дорогою, використовую -exec звичайно.
Майкл Саккі

це не в режимі реального часу. в реальному часі завжди найкраще
Farhan

3
Найкраще рішення, якщо inotifyйого немає. Я хотів би додати лише -type fдля фільтрування файлів. Інакше папка також буде повернута.
Сяо Пен - ZenUML.com

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

17

Ви можете використовувати watchу своєму сценарії

watch -n 0.1 ls <your_folder>

Переглядає вашу папку і перераховує все, що в ній, кожні 0,1 секунди

Недолік

Це не в режимі реального часу, тому якщо файл був створений та видалений менш ніж за 0,1 секунди, це не працює, watchпідтримує лише 0,1 секунди.


Саме це я намагався запам’ятати! Дуже дякую!!
Joabe Lucena

9

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

Можна використовувати таку команду:

ls -1A isempty | wc -l

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

Це сказало нерозумно, якщо тест може зробити решту роботи:

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 . Цей метод заснований на інотифікації. Існує параметр 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Запуск у неінтерактивному режимі. У цьому режимі записувач не намагається прочитати з TTY або змінити його властивості.
  • -r Перезавантажте стійкий дочірні процес. Як і у стандартному режимі роботи, утиліта, яка закінчується, не виконується знову, поки не буде оброблена подія файлової системи або клавіатури. SIGTERMвикористовується для припинення утиліти до її перезапуску. Група процесів створюється для запобігання скриптам оболонки від маскування сигналів. entrчекає, поки утиліта вийде, щоб забезпечити закриття таких ресурсів, як сокети. Контроль TTY не передається дочірньому процесу.

2

Bash не може це зробити легко. Потрібно в основному отримати список усіх файлів у папці та періодично отримувати новий список і порівнювати їх, щоб побачити, що змінилося.

Те, що ви шукаєте, називається inotify. Його вбудовано в ядро ​​Linux, і ви можете сидіти там, чекаючи, коли щось станеться, і після цього inotify повернеться і каже: "ей, є новий файл під назвою foobar"

Щоб здійснити те, що ви хочете, вам доведеться перейти на щось на кшталт perl і використовувати Linux :: Inotify2 (python, мабуть, підтримує ініціативу, але я - людина перл).


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

Нижче наведена скорочена версія прикладу для stackoverflow, яку я перевірив та включив до одного з моїх проектів, який вимагає моніторингу конкретних каталогів.

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.