Próbuję napisać skrypt powłoki, który będzie oczekiwał na pojawienie się pliku w /tmp
katalogu o nazwie, sleep.txt
a gdy go znajdzie, program przestanie działać, w przeciwnym razie chcę, aby program był w stanie uśpienia (zawieszenia) do momentu zlokalizowania pliku . Teraz zakładam, że użyję polecenia testowego. Coś w stylu
(if [ -f "/tmp/sleep.txt" ];
then stop
else sleep.)
Jestem zupełnie nowy w pisaniu skryptów powłoki i każda pomoc jest mile widziana!
shell-script
files
Mo Gainz
źródło
źródło
$MAILPATH
.Odpowiedzi:
Pod Linuksem możesz użyć podsystemu jądra inotify, aby efektywnie czekać na pojawienie się pliku w katalogu:
(przy założeniu Bash dla
<()
składni przekierowania wyjściowego)Zaletą tego podejścia w porównaniu do odpytywania w ustalonych odstępach czasu, jak w
jest to, że jądro śpi więcej. Dzięki specyfikacji zdarzenia inotify, takiej jak
create,open
skrypt, jest właśnie zaplanowany do wykonania po/tmp
utworzeniu lub otwarciu pliku poniżej . Dzięki ustalonemu odpytywaniu przedziału czasu marnujesz cykle procesora dla każdego przyrostu czasu.Zawarłem
open
zdarzenie, aby zarejestrować się,touch /tmp/sleep.txt
gdy plik już istnieje.źródło
inotifywait -e create,open --format '%f' --quiet /tmp/sleep.txt --monitor > /dev/null ; # continues once /tmp/sleep.txt is created/opened
?inotifywait
jest pętlą while i wyświetla linię za każdym razem, gdy plik jest otwierany / tworzony. Więc potrzebujesz pętli while, aby przerwać, gdy zostanie zmieniona.sleep.txt
w pewnym momencie. Zatem nie ma warunków rasowych. Pytanie nie zawiera niczego, co sugerowałoby scenariusz, który masz na myśli.Po prostu umieść test w
while
pętli:źródło
sleep
to liczba sekund oczekiwania w każdej iteracji - możesz to zmienić w zależności od potrzeb.Istnieje kilka problemów z niektórymi dotychczasowymi
inotifywait
podejściami opartymi na:sleep.txt
pliku, który został najpierw utworzony jako nazwa tymczasowa, a następnie zmieniono jego nazwę nasleep.txt
.moved_to
Oprócz tego trzeba dopasować do wydarzeńcreate
sleep.txt
został utworzony. Co jeśli na przykładfoo\nsleep.txt\nbar
plik został utworzony?inotifywait
uruchomieniem i zainstalowaniem zegarka? Poteminotifywait
czekałby wiecznie na plik, który już tu jest. Musisz upewnić się, że pliku już nie ma po zainstalowaniu zegarka.inotifywait
działać (przynajmniej do momentu utworzenia innego pliku) po znalezieniu pliku.Aby rozwiązać te problemy, możesz:
Zauważ, że obserwujemy tworzenie
sleep.txt
w bieżącym katalogu.
(więc zrobiłbyś tocd /tmp || exit
wcześniej w swoim przykładzie). Bieżący katalog nigdy się nie zmienia, więc gdy ten rurociąg potoczy się pomyślnie, znajduje sięsleep.txt
w utworzonym katalogu bieżącym.Oczywiście, można zastąpić
.
z/tmp
powyżej, ale gdyinotifywait
jest uruchomiony,/tmp
mogła zostać zmieniona na kilka razy (mało prawdopodobne/tmp
, ale coś do rozważenia w przypadku ogólnym) lub nowy system plików zamontowany na nim, więc kiedy wraca do rurociągów, nie mogą być/tmp/sleep.txt
stworzonym, ale/new-name-for-the-original-tmp/sleep.txt
zamiast niego. W/tmp
tym przedziale czasu można także utworzyć nowy katalog, którego nie można oglądać, więcsleep.txt
utworzony tam katalog nie zostanie wykryty.źródło
Akceptowana odpowiedź naprawdę działa (dzięki maxschlepzig), ale pozostawia monitorowanie inotifywait w tle, dopóki skrypt nie zakończy działania. Jedyną odpowiedzią, która dokładnie odpowiada twoim wymaganiom (tj. Oczekiwanie na pojawienie się pliku sleep.txt w / tmp) wydaje się być odpowiedź Stephane'a, jeśli katalog, który ma być monitorowany przez inotifywait, zostanie zmieniony z kropki (.) Na '/ tmp'.
Jeśli jednak chcesz użyć katalogu tymczasowego TYLKO do umieszczenia flagi sleep.txt i możesz się założyć, że nikt inny nie umieści żadnego pliku w tym katalogu, wystarczy poprosić inotifywait o obejrzenie tego katalogu pod kątem tworzenia plików:
Pierwszy krok: utwórz katalog, który będziesz monitorować:
Drugi krok: upewnij się, że katalog naprawdę tam jest
Trzeci krok: poczekaj, aż pojawi się ŻADNY plik
$directoryToPutSleepFile
Plik, który umieścisz,
$directoryToPutSleepFile
może mieć nazwę sleep.txt awake.txt, cokolwiek. Moment utworzenia dowolnego pliku w$directoryToPutSleepFile
skrypcie będzie przebiegał pozainotifywait
instrukcją.źródło
sleep.txt
utworzenie między dwoma wywołaniami inotifywait.sleep.txt
zostanie utworzony plik o nazwie . Spróbuj na przykładtouch /tmp/foo /tmp/sleep.txt
, wtedy jedno wystąpienieinotifywait
zgłosifoo
i zakończy działanie, a do czasu uruchomienia następnego inotifywait sleep.txt już długo tam będzie, więc inotifywait nie wykryje jego utworzenia.ogólnie rzecz biorąc, bardzo trudno jest uczynić cokolwiek innego niż prostą pętlę test / sen. Głównym problemem jest to, że test będzie się ścigał z tworzeniem pliku - chyba że test się powtórzy, zdarzenie tworzenia może zostać pominięte. Jest to zdecydowanie najlepszy wybór w większości przypadków, w których powinieneś używać Shell na początek:
Jeśli okaże się, że jest to niewystarczające ze względu na problemy z wydajnością, to użycie Shell prawdopodobnie nie jest dobrym pomysłem.
źródło
W oparciu o zaakceptowaną odpowiedź maxschlepzig (i pomysł z zaakceptowanej odpowiedzi na /superuser/270529/monitoring-a-file-until-a-string-is-found ) proponuję następujące ulepszenia ( moim zdaniem) odpowiedź, która może również działać z limitem czasu:
W przypadku, gdy plik nie zostanie utworzony / otwarty w podanym limicie czasu, status wyjścia to 124 (zgodnie z dokumentacją limitu czasu (strona podręcznika)). W przypadku, gdy zostanie utworzony / otwarty, kodem wyjścia jest 0 (sukces).
Tak, inotifywait działa w ten sposób w podpowłoce i ta podpowłoka zakończy działanie dopiero po przekroczeniu limitu czasu lub po zakończeniu skryptu głównego (w zależności od tego, co nastąpi wcześniej).
źródło