Як виявити нові файли в папці зі скриптом bash ? Я хотів би обробити файли, як тільки вони створені в папці. Чи можливо це зробити чи мені потрібно запланувати скрипт із кроном, який щохвилини перевіряє наявність нових файлів?
Як виявити нові файли в папці зі скриптом bash ? Я хотів би обробити файли, як тільки вони створені в папці. Чи можливо це зробити чи мені потрібно запланувати скрипт із кроном, який щохвилини перевіряє наявність нових файлів?
Відповіді:
Слід розглянути можливість використання 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 для попередньої обробки виводу.
inotifywait
було саме те, що я хотів.
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 |
я спробую відредагувати цю відповідь.
fswatch
. Я його не писав, але це відкритий код і я його використовую.
Я вважаю за краще 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/
Я щойно підготував це, і не бачу з цим величезних проблем, окрім крихітного шансу пропустити файли між чеками.
while true
do
touch ./lastwatch
sleep 10
find /YOUR/WATCH/PATH -cnewer ./lastwatch -exec SOMECOMMAND {} \;
done
Якщо обробка вашого файлу не займе багато часу, ви не повинні пропустити жоден новий файл. Ви також можете переглядати діяльність ... Це не куленепробивна, але вона виконує деякі цілі без зовнішніх інструментів, таких як ініціація.
inotify
його немає. Я хотів би додати лише -type f
для фільтрування файлів. Інакше папка також буде повернута.
-f filename
варіант чудовий. Тоді єдине питання, що залишається - як це почати після перезавантаження. Я збираюся використовувати це зі своєю сонячною установкою, щоб os.system("ssh me@mysystem ' ( touch /home/me/alarms/low24 ) '")
тоді створення цього файлу призвело до використання головним комп'ютером espeak
і оголосить про низьку напругу. Він вже надсилає мені електронний лист, але оскільки моя система вже говорить про час у верхній частині години, у нього є все інше. askubuntu.com/questions/977613/…
Ви можете використовувати watch
у своєму сценарії
watch -n 0.1 ls <your_folder>
Переглядає вашу папку і перераховує все, що в ній, кожні 0,1 секунди
Недолік
Це не в режимі реального часу, тому якщо файл був створений та видалений менш ніж за 0,1 секунди, це не працює, watch
підтримує лише 0,1 секунди.
Я припускаю, що цільова папка (я буду називати це 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
Якщо ви хочете виявити нові файли, то обробіть їх і в кінці видаліть файли, що дійшли, ви можете використовувати 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.
Він заснований на моніторингу доступу до файлів чайників
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 не передається дочірньому процесу.
Bash не може це зробити легко. Потрібно в основному отримати список усіх файлів у папці та періодично отримувати новий список і порівнювати їх, щоб побачити, що змінилося.
Те, що ви шукаєте, називається inotify. Його вбудовано в ядро Linux, і ви можете сидіти там, чекаючи, коли щось станеться, і після цього inotify повернеться і каже: "ей, є новий файл під назвою foobar"
Щоб здійснити те, що ви хочете, вам доведеться перейти на щось на кшталт perl і використовувати Linux :: Inotify2 (python, мабуть, підтримує ініціативу, але я - людина перл).
Це працює в 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
Нижче наведена скорочена версія прикладу для 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; вищезгаданий проект.