Skrypt do monitorowania folderu pod kątem nowych plików?

127

Jak wykryć nowe pliki w folderze ze skryptem ? Chciałbym przetworzyć pliki, jak tylko zostaną utworzone w folderze. Czy to możliwe, czy muszę zaplanować skrypt z który co minutę sprawdza nowe pliki?

ihatetoregister
źródło
1
Czy zamierzasz usunąć pliki z folderu po ich przetworzeniu?
ztank1013,

Odpowiedzi:

151

Powinieneś rozważyć użycie inotifywaitjako przykładu:

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

W Ubuntu inotifywaitzapewnia inotify-toolspakiet. Od wersji 3.13 (bieżącej w Ubuntu 12.04) inotifywaitbędzie zawierać nazwę pliku bez opcji -f. Starsze wersje mogą wymagać przymusu. Należy zauważyć, że -eopcja inotifywaitjest najlepszym sposobem filtrowania zdarzeń. Ponadto twoje readpolecenie może przypisać dane wyjściowe pozycji do wielu zmiennych, które możesz użyć lub zignorować. Nie ma potrzeby używania grep / sed / awk do wstępnego przetwarzania danych wyjściowych.

enzotib
źródło
1
Wspaniały! inotifywaitByło tylko to, co chciałem.
ihatetoregister
2
Po prostu chcę to zaktualizować. Nie potrzebujesz awk, aby to osiągnąć. możesz filtrować zdarzenia za pomocą „-e create” i uzyskać tylko nazwę pliku, wykonując „-f% f” lub pełną ścieżkę za pomocą „-f% w% f”. Tak więc pierwsza linia powyższego skryptu brzmi: inotifywait -m / ścieżka -f% w% f -e create |
Lugoues,
2
@Lugoues, a teraz, kiedy spróbujesz użyć -f dostajesz The '--filename' option no longer exists. The option it enabled in earlier versions of inotifywait is now turned on by default.Więc musisz tylko zrobić, inotifywait -m /path -e create |ja spróbuję edytować tę odpowiedź.
Bruno Bronosky,
1
Teraz istnieje także przenośne narzędzie o nazwie fswatch. Nie napisałem tego, ale jest to oprogramowanie typu open source i korzystam z niego.
1
@Wender inotfiywait po uruchomieniu wyświetla 3 informacje w jednym wierszu. Wbudowane bash „read” odczytuje linię wejściową i przypisuje każdą z trzech informacji do zmiennej. Zatem pierwszy element jest przypisany do ścieżki zmiennej, drugi do działania, a trzeci do pliku. Po przypisaniu wartości do tych zmiennych są one następnie dostępne do późniejszego wykorzystania (jak na linii echa). Więcej informacji: tldp.org/LDP/Bash-Beginners-Guide/html/sect_08_02.html
Tim
26

Wolę incron, ponieważ jest łatwiejszy w zarządzaniu. Zasadniczo jest to usługa, która wykorzystuje inotifyi możesz konfigurować konfiguracje, aby podejmować działania w oparciu o operacje zmiany plików.

Dawny:

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

Pełny przykład możesz zobaczyć tutaj: http://www.cyberciti.biz/faq/linux-inotify-examples-to-replicate-directories/

rynop
źródło
24

Właśnie to ugotowałem i nie widzę z tym żadnych większych problemów, poza niewielką szansą na brakujące pliki między czekami.

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

Jeśli przetwarzanie pliku nie trwa zbyt długo, nie możesz przegapić żadnego nowego pliku. Możesz także przedstawić działania w tle ... Nie jest to kuloodporne, ale służy pewnym celom bez zewnętrznych narzędzi, takich jak inotify.

Michael Sacchi
źródło
Dobry chwyt Ulepszyłem go nieco, by obsługiwał spacje w nazwach plików.
Michael Sacchi,
Absolutnie. To jest właściwa droga. Nie bardzo wiem, dlaczego poszedłem tą drogą, używam -exec rutynowo.
Michael Sacchi,
to nie jest w czasie rzeczywistym. czas rzeczywisty jest zawsze najlepszy
Farhan,
3
Najlepsze rozwiązanie, jeśli inotifynie jest dostępne. Dodałbym, -type faby odfiltrować tylko pliki. W przeciwnym razie folder również zostanie zwrócony.
Xiao Peng - ZenUML.com
Tak - -f filenameopcja jest świetna. Pozostaje więc tylko pytanie, jak to zrobić, aby ponownie uruchomić komputer. Zamierzam użyć tego z moją elektrownią słoneczną, aby os.system("ssh me@mysystem ' ( touch /home/me/alarms/low24 ) '")następnie utworzenie tego pliku spowodowało, że komputer główny użyje espeaki ogłosi niskie napięcie. Już wysyła mi wiadomość e-mail, ale ponieważ mój system już mówi godzinę w szczycie, ma całą resztę. askubuntu.com/questions/977613/…
SDsolar
17

Możesz użyć watchw swoim skrypcie

watch -n 0.1 ls <your_folder>

Monitoruje folder i wyświetla wszystko w nim co 0,1 sekundy

Wada

To nie jest czas rzeczywisty, więc jeśli plik został utworzony i usunięty w mniej niż 0,1 sekundy, to nie działałoby, watchobsługuje tylko 0,1 sekundy.

Cygański kosmonauta
źródło
Właśnie to starałem się zapamiętać! Wielkie dzięki!!
Joabe Lucena
9

Zakładam, że folder docelowy (nazywam to isemptydla wygody) jest pusty i czekasz na upuszczenie jednego lub więcej plików.

Możesz użyć następującego polecenia:

ls -1A isempty | wc -l

po prostu, aby sprawdzić, czy folder jest nadal pusty, w rzeczywistości zwróci 0, jeśli nie ma nowego pliku (stąd isemptyfolder jest nadal pusty) lub, z drugiej strony, zwróci wartość większą niż 0 (w rzeczywistości liczba plików aktualnie znajdujących się w folderze).

To powiedziawszy głupi test „jeśli / to” może zrobić resztę pracy:

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

Oczywiście do_somethingfunkcja będzie musiała manipulować plikami w isemptyfolderze, a następnie usunąć go (same) z samego folderu po przetworzeniu.

Dodanie do tabeli crontab wiersza takiego jak poniższy uruchomi sprawdzanie raz na minutę i uruchomi do_somethingakcję, jeśli folder nie jest oczywiście pusty:

* * * * *     if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi
ztank1013
źródło
To rozwiązanie działa w przypadku zamontowanych zdalnych systemów plików. Deweloperzy inotify-tools pracują nad bezpiecznikiem (lub był w połowie 2014 roku).
Rondo
3
Nie powinieneś nigdy używać lsskryptów. findZamiast tego użyj prostego globowania: mywiki.wooledge.org/ParsingLs
andsens
6

Jeśli chcesz wykryć nowe pliki, przetwórz je, a na koniec usuń kontynuowane pliki, możesz użyć systemd.path . Ta metoda opiera się na inotify. Istnieje opcja DirectoryNotEmpty, więc systemd może uruchomić skrypt zawsze, gdy wykryje jakieś pliki w katalogu. Musisz pamiętać, że to zadziała tylko wtedy, gdy będziesz mógł usunąć pliki i skrypt pozostawi katalog pusty.

Najpierw przygotuj plik mymonitor.service

[Unit]
Description=Start the script

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

następnie przejdź do mymonitor.path, aby zdefiniować ścieżkę

[Unit]
Description= Triggers the service

[Path]
DirectoryNotEmpty=/path/to/monitor

[Install]
WantedBy=multi-user.target

Jeśli nazwa pliku .path jest taka sama jak nazwa usługi, nie ma potrzeby określania nazwy usługi w pliku .path.

Opiera się na monitorowaniu dostępu do plików dla manekinów

Dawid Wolski
źródło
4

entr

Używanie entrto nowy sposób na zrobienie tego (jest to platforma wieloplatformowa). Uwaga entrnie używa odpytywania, co daje ogromną przewagę nad wieloma alternatywami.

Wykorzystuje kqueue(2)lub, inotify(7)aby uniknąć odpytywania. entrzostał napisany, aby szybkie sprzężenie zwrotne i automatyczne testy były naturalne i całkowicie zwyczajne.

Na BSD używa pledge(2)

Możesz go zainstalować za pomocą

apt-get install entr
dnf install entr

Możesz śledzić katalog nowych dodatków za pomocą

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

Opcje wyjaśnione (z dokumentów),

  • -d Śledź katalogi zwykłych plików podanych jako dane wejściowe i zakończ, jeśli zostanie dodany nowy plik. Ta opcja umożliwia także jawne określenie katalogów. Pliki o nazwach rozpoczynających się od „.” są ignorowane.
  • -nUruchom w trybie nieinteraktywnym. W tym trybie entr nie próbuje czytać z TTY ani zmieniać jego właściwości.
  • -r Załaduj ponownie trwały proces potomny. Podobnie jak w przypadku standardowego trybu działania, narzędzie, które kończy działanie, nie jest uruchamiane ponownie, dopóki nie zostanie przetworzone zdarzenie systemu plików lub klawiatury. SIGTERMsłuży do zakończenia działania narzędzia przed jego ponownym uruchomieniem. Utworzono grupę procesów, aby uniemożliwić skryptom powłoki maskowanie sygnałów. entrczeka na zamknięcie narzędzia, aby upewnić się, że zasoby takie jak gniazda zostały zamknięte. Kontrola nad TTY nie jest przenoszona na proces potomny.
Evan Carroll
źródło
2

Bash nie może tego łatwo zrobić. Musisz w zasadzie uzyskać listę wszystkich plików w folderze i okresowo uzyskać nową listę i porównać je, aby zobaczyć, co się zmieniło.

To, czego szukasz, nazywa się inotify. Jest wbudowany w jądro Linuksa i możesz w zasadzie siedzieć i czekać, aż coś się wydarzy, w którym wraca funkcja inotify i mówi „hej, jest nowy plik o nazwie foobar”

Aby osiągnąć to, co chcesz, musisz przełączyć się na coś takiego jak Perl i użyć Linux :: Inotify2 (python prawdopodobnie również obsługuje inotify, ale jestem osobą perla).

Patrick
źródło
0

Działa to w cygwin i Linux. Niektóre z poprzednich rozwiązań, które zapisują plik, spowodują uszkodzenie dysku. Ten scipt nie ma tego problemu:

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
użytkownik1186515
źródło
0

Poniżej znajduje się skrócona wersja przykładu przepływu stosu , który przetestowałem i włączyłem do jednego z moich projektów, który wymaga monitorowania określonych katalogów.

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
}

Oto link do skryptu, który używa zmodyfikowanej wersji powyższej do automatycznego odszyfrowywania plików lub katalogów znajdujących się w punkcie montowania sshfs; wyżej wspomniany projekt.

S0AndS0
źródło