Jak automatycznie uruchomić skrypt, gdy zawartość katalogu zmienia się w systemie Linux?

17

Chcę automatycznie uruchamiać skrypt za każdym razem, gdy nowe pliki są kopiowane do określonego katalogu. Innymi słowy, czy jest sposób w Linuksie, aby „obserwować” katalog zmian, a następnie uruchomić coś w odpowiedzi na zmianę?

GeneQ
źródło
Ta dyskusja odbywa się na każdej stronie
Stackexchange

Odpowiedzi:

17

Jeśli masz szczęście wystarczy być na dystrybucji Debiana opartej apt-get install dnotify. Inne dystrybucje prawdopodobnie mają coś podobnego - poszukaj dnotifynazwy.

dnotify to prosty program oparty na API dnotify API jądra Linuksa 2.4.19 +. dnotify może wykonać określone polecenie za każdym razem, gdy zmienia się zawartość określonego katalogu. Jest uruchamiany z wiersza poleceń i przyjmuje dwa argumenty: jeden lub więcej katalogów do monitorowania i polecenie do wykonania przy każdej zmianie katalogu. Opcje kontrolują, jakie zdarzenia mają być uruchamiane: kiedy plik został odczytany w katalogu, kiedy został utworzony, usunięty i tak dalej.

Jeśli chcesz poradzić sobie z tym w swoim własnym programie, dnotify to także interfejs API, którego chcesz użyć.

MikeyB
źródło
4
@MikeB, po tym, jak zasugerowałem Ci, że Google go powiadomił, skończyłem na inotify, który najwyraźniej go wyprzedza. Dzięki za wskazanie mi właściwego kierunku. apt-get install inotify-tools
GeneQ
7
@GeneQ, inotify zastąpił dnotify.
David
1
Podobnie w Gentoo:emerge inotify-tools
James Sneeringer,
Tak, miałem zamiar powiedzieć, jądro 2.4.19 jest trochę starożytne ;-) inotify jest właściwą drogą.
David Z
O tak ... Zapomniałem, co było nowsze :)
MikeyB
12

Możesz uruchomić skrypt za pomocą narzędzi inotify, coś takiego. Będzie obserwował katalog pod kątem zmian w zmodyfikowanych plikach, nowych i usuniętych plikach, a następnie wykona skrypt.

#!/bin/sh
while inotifywait -e modify -e create -e delete /home/me/code; do
    rsync [options] /home/me/code/ /media/nfs/code/ 
done
użytkownik7119
źródło
Wystarczy wziąć pod uwagę, że jeśli katalog źródłowy zmieni się podczas kopiowania, inotifywait NIE zobaczy go, a zmiany te nie zostaną skopiowane, dopóki dalsze zmiany nie zostaną zakończone. Prawdopodobnie nie stanowi to problemu.
Raúl Salinas-Monteagudo
Jak uruchomić to w trybie demona?
Chris F,
4

myślę, że incron jest w zasadzie tym, czego chcesz. Używa inotify jako mechanizmu powiadamiania (który, jak zauważyli inni, zastępuje dnotify), ale nie wymaga skryptu, który działa w sposób ciągły, używając inotifywait lub podobnego (choć oczywiście demon incron cały czas działa). Ogólnosystemowe „crontabs” i „crontabs” użytkownika są obsługiwane w podobny sposób jak standardowy cron, ale zamiast określania czasów jako wyzwalaczy, używane są zdarzenia inotify oraz nazwy plików / katalogów.

incron jest spakowany dla wielu dystrybucji, w tym, jak sądzę, Ubuntu i Debian.

Andrew Ferrier
źródło
0

Istnieje oprogramowanie przeznaczone wyłącznie do tego celu, autoenv Możesz to sprawdzić.

DukeLion
źródło
0

entr jest najprostszym i najbardziej składalnym narzędziem do powiadamiania o plikach, jakie widziałem. Jego użycie jest zoptymalizowane do oglądania plików, a nie katalogów, ale może również rozwiązać twoją sprawę.

Aby wykryć i działać na dodanym pliku, połącz go z innymi narzędziami, takimi jak np make. entrnie wysyła nazwy ani nic podobnego, po prostu uruchamia to, co kazałeś uruchomić.

Aby sprawdzić dodane pliki w katalogu:

## entr exits with rc=0 when terminated
## rc=1 when watched files go away or don't exist to begin with
## rc=2 when new files arrive in watched directories
until echo /path/to/directory_to_watch | entr -d do_stuff
do sleep 1; done

Jeśli chcesz działać również w przypadku zmiany istniejącego pliku:

## Here's why it comes in handy that entr exits when new files are added --
## find gets re-run.
until find /path/to/directory_to_watch/ -path /path/to/directory_to_watch/* |
    entr -d do_stuff
do sleep 1; done

... i tu przydaje się mechanizm pętli, ponieważ findwyrażenie zostanie uruchomione ponownie, jeśli plik zostanie dodany.

Jeśli chcesz poprawić obsługę błędów i upewnić się, że wszystko działa tylko raz dla dodanego / usuniętego pliku, robi się nieco dziwacznie, ale w tych prostych przypadkach jest genialny.


EDYCJA: Jeśli chcesz to zrobić na poziomie systemu, na przykład incron , po prostu dodaj skrypt do swojego ulubionego menedżera procesów (takiego jak s6 , runit , systemd lub sysvinit i pomiń pętlę:

#!/bin/bash
exec entr -d do_stuff < <(find /path/to/directory_to_watch/ -path /path/to/directory_to_watch/*)

Funkcje execoraz proces podstawiania ( <(...)) są ważne podczas uruchamiania z menedżera procesów, aby poprawnie obsługiwać sygnalizację (tj. Aby usunąć powłokę z drogi).

clacke
źródło