Ich versuche, ein Shell-Skript zu schreiben, das darauf wartet, dass eine Datei in dem /tmp
aufgerufenen Verzeichnis angezeigt wird, sleep.txt
und sobald es gefunden wird, wird das Programm beendet . Nun gehe ich davon aus, dass ich einen Testbefehl verwenden werde. So etwas wie
(if [ -f "/tmp/sleep.txt" ];
then stop
else sleep.)
Ich bin brandneu im Schreiben von Shell-Skripten und jede Hilfe wird sehr geschätzt!
shell-script
files
Mo Gainz
quelle
quelle
$MAILPATH
.Antworten:
Unter Linux können Sie das inotify- Kernel-Subsystem verwenden, um effizient auf das Erscheinen einer Datei in einem Verzeichnis zu warten:
(unter der Annahme von Bash für die
<()
Ausgabeumleitungssyntax)Der Vorteil dieses Ansatzes im Vergleich zum festen Zeitintervall Polling wie in
ist, dass der Kernel mehr schläft. Bei einer inotify-Ereignisspezifikation
create,open
ist die Ausführung des Skripts nur dann geplant, wenn eine Datei unter/tmp
erstellt oder geöffnet wird. Mit dem festen Zeitintervall-Polling verschwenden Sie CPU-Zyklen für jedes Zeitinkrement.Ich habe das
open
Ereignis aufgenommen, um mich auch zu registrieren,touch /tmp/sleep.txt
wenn die Datei bereits existiert.quelle
inotifywait -e create,open --format '%f' --quiet /tmp/sleep.txt --monitor > /dev/null ; # continues once /tmp/sleep.txt is created/opened
?inotifywait
ist selbst eine while-Schleife und gibt bei jedem Öffnen / Erstellen der Datei eine Zeile aus. Die while-Schleife muss also unterbrochen werden, wenn sie geändert wird.sleep.txt
zu einem bestimmten Zeitpunkt ausgeführt wird. Somit keine Racebedingung. Die Frage enthält keine Hinweise auf ein bestimmtes Szenario.Setzen Sie einfach Ihren Test in die
while
Schleife:quelle
sleep
ist die Anzahl der Sekunden, die in jeder Iteration gewartet werden muss. Sie können dies je nach Ihren Anforderungen ändern.Es gibt ein paar Probleme mit einigen der
inotifywait
bisher gegebenen Ansätze:sleep.txt
Datei finden, die zuerst als temporärer Name erstellt und dann in umbenannt wurdesleep.txt
. Man muss fürmoved_to
Events zusätzlich passencreate
sleep.txt
erstellt wurde. Was ist, wenn zum Beispiel einefoo\nsleep.txt\nbar
Datei erstellt wurde?inotifywait
die Uhr gestartet und installiert wurde? Danninotifywait
würde ewig auf eine Datei warten, die schon hier ist. Sie müssen sicherstellen, dass die Datei nach der Installation der Uhr noch nicht vorhanden ist.inotifywait
ausgeführt (mindestens bis eine andere Datei erstellt wurde), nachdem die Datei gefunden wurde.Um diese zu beheben, können Sie Folgendes tun:
Beachten Sie, dass wir
sleep.txt
im aktuellen Verzeichnis nach der Erstellung von.
suchen (cd /tmp || exit
in Ihrem Beispiel haben Sie das also bereits getan ). Das aktuelle Verzeichnis wird nie geändert. Wenn diese Pipeline erfolgreich zurückgegeben wird, befindet sie sichsleep.txt
in dem aktuellen Verzeichnis, das erstellt wurde.Natürlich können Sie ersetzen
.
mit/tmp
oben, aber währendinotifywait
ausgeführt wird ,/tmp
wurde mehrmals umbenannt hätte (für unwahrscheinlich/tmp
, aber etwas im allgemeinen Fall zu betrachten) oder ein neues Dateisystem gemountet drauf, also , wenn die Pipeline zurückkehrt, kann es nicht Sei ein/tmp/sleep.txt
, der erschaffen wurde, sondern ein/new-name-for-the-original-tmp/sleep.txt
. Es/tmp
könnte auch ein neues Verzeichnis in dem Intervall erstellt worden sein, und dieses würde nicht überwacht, so dass ein dortsleep.txt
erstelltes Verzeichnis nicht erkannt würde.quelle
Die akzeptierte Antwort funktioniert wirklich (danke maxschlepzig), aber die inotifywait-Überwachung bleibt im Hintergrund, bis Ihr Skript beendet wird. Die einzige Antwort, die genau Ihren Anforderungen entspricht (dh darauf zu warten, dass sleep.txt in / tmp angezeigt wird), scheint die von Stephane zu sein, wenn das von inotifywait zu überwachende Verzeichnis von Punkt (.) In '/ tmp' geändert wird.
Wenn Sie jedoch bereit sind, ein temporäres Verzeichnis NUR zum Setzen Ihres sleep.txt-Flags zu verwenden und wetten können, dass niemand anderes eine Datei in dieses Verzeichnis legt, reicht es aus, inotifywait zu bitten, dieses Verzeichnis auf Dateierzeugungen zu überwachen:
1. Schritt: Erstellen Sie das zu überwachende Verzeichnis:
2. Schritt: Stellen Sie sicher, dass das Verzeichnis wirklich vorhanden ist
3. Schritt: Warten Sie, bis JEDE Datei angezeigt wird
$directoryToPutSleepFile
Die Datei, die Sie
$directoryToPutSleepFile
einfügen, kann den Namen sleep.txt awake.txt haben. In dem Moment, in dem eine Datei in$directoryToPutSleepFile
Ihrem Skript erstellt wird, wird dieinotifywait
Anweisung fortgesetzt .quelle
sleep.txt
fehlschlägt , wenn kurz zuvor eine andere erstellt wurde, und die Datei zwischen zwei inotifywait-Aufrufen erstellt wird.sleep.txt
erstellt wird. Versuchen Sie zum Beispieltouch /tmp/foo /tmp/sleep.txt
, dass eine Instanz voninotifywait
meldetfoo
und beendet wird. Zum Zeitpunkt des nächsten Starts von inotifywait ist die Datei sleep.txt bereits seit langem vorhanden, sodass inotifywait ihre Erstellung nicht erkennt.Im Allgemeinen ist es ziemlich schwierig, etwas anderes als die einfache Test- / Schlafschleife zuverlässig zu machen. Das Hauptproblem besteht darin, dass der Test mit der Erstellung der Datei beginnt. Wenn der Test nicht wiederholt wird, kann das Erstellungsereignis übersehen werden. Dies ist bei weitem die beste Wahl in den meisten Fällen, in denen Sie zunächst Shell verwenden würden:
Wenn Sie feststellen, dass dies aufgrund von Leistungsproblemen nicht ausreicht, ist die Verwendung von Shell wahrscheinlich keine gute Idee.
quelle
Basierend auf der akzeptierten Antwort von maxschlepzig (und einer Idee aus der akzeptierten Antwort unter /superuser/270529/monitoring-a-file-until-a-string-is-found ) schlage ich Folgendes vor: aus meiner sicht) antwort was auch mit timeout klappen kann:
Falls die Datei nicht innerhalb des angegebenen Timeouts erstellt / geöffnet wird, lautet der Beendigungsstatus 124 (gemäß Timeout-Dokumentation (Manpage)). Wenn es erstellt / geöffnet wird, ist der Exit-Status 0 (Erfolg).
Ja, inotifywait wird auf diese Weise in einer Sub-Shell ausgeführt und diese Sub-Shell wird erst beendet, wenn das Timeout auftritt oder wenn das Hauptskript beendet wird (je nachdem, was zuerst eintritt).
quelle