Gibt es eine integrierte Funktion in Bash, die darauf wartet, dass ein Prozess abgeschlossen ist?
Mit dem wait
Befehl kann nur gewartet werden, bis untergeordnete Prozesse abgeschlossen sind. Ich würde gerne wissen, ob es eine Möglichkeit gibt, auf den Abschluss eines Prozesses zu warten, bevor Sie mit einem Skript fortfahren.
Ein mechanischer Weg, dies zu tun, ist wie folgt, aber ich würde gerne wissen, ob es in Bash eine eingebaute Funktion gibt.
while ps -p `cat $PID_FILE` > /dev/null; do sleep 1; done
Antworten:
Warten, bis ein Vorgang abgeschlossen ist
Linux:
Darwin (erfordert, dass
$pid
offene Dateien hat):Mit Zeitüberschreitung (Sekunden)
Linux:
Darwin (erfordert, dass
$pid
offene Dateien hat):quelle
tail
würde das tun.tail
arbeitet unter der Haube durch Abfragen mitkill(pid, SIG_0)
einem Prozess (entdeckt mitstrace
).+r 1
ist das Timeout. Ich persönlich suche nach einer Lösung für MacOS, die kein Polling verwendet.tail
hat die Liniekill (pid, 0) != 0 && errno != EPERM
.caffeinate -w $pid
.Es gibt keine eingebauten. Verwendung
kill -0
in einer Schleife für eine praktikable Lösung:Oder als einfacher Oneliner für die einfache einmalige Verwendung:
Wie mehrere Kommentatoren festgestellt haben, haben Sie eine andere Möglichkeit gefunden, um festzustellen, ob der Prozess ausgeführt wird, um den
kill -0 $pid
Aufruf zu ersetzen, wenn Sie auf Prozesse warten möchten, an die Sie keine Berechtigung zum Senden von Signalen haben . Funktioniert unter Linux,test -d "/proc/$pid"
auf anderen Systemen, die Sie möglicherweise verwenden müssenpgrep
(falls verfügbar) oder ähnlichesps | grep "^$pid "
.quelle
sleep 0.5
kann der Prozess mit$pid
sterben und ein anderer Prozess kann mit demselben erstellt werden$pid
. Und am Ende warten wir auf zwei verschiedene Prozesse (oder sogar mehr) mit demselben$pid
.Ich habe festgestellt, dass "kill -0" nicht funktioniert, wenn der Prozess root (oder einem anderen) gehört. Deshalb habe ich pgrep verwendet und mir Folgendes ausgedacht:
Dies hätte den Nachteil, dass wahrscheinlich Zombie-Prozesse übereinstimmen.
quelle
kill(pid, sig=0)
schlägt der Systemaufruf fehl, wenn der Aufruferprozess keine Berechtigung zum Beenden hat. Somit schlagen / bin / kill -0 und "kill -0" (eingebauter Bash) unter denselben Bedingungen ebenfalls fehl.Diese Bash-Skriptschleife endet, wenn der Prozess nicht vorhanden ist oder es sich um einen Zombie handelt.
EDIT : Das obige Skript wurde unten von Rockallite gegeben . Vielen Dank!
Meine ursprüngliche Antwort unten funktioniert für Linux und basiert auf
procfs
dh/proc/
. Ich kenne die Portabilität nicht:Es ist nicht auf die Shell beschränkt, aber die Betriebssysteme selbst haben keine Systemaufrufe, um die Beendigung von nicht untergeordneten Prozessen zu überwachen.
quelle
grep /proc/$PID/status
mit doppelten Anführungszeichen (bash: test: argument expected
) umgeben musstewhile s=`ps -p $PID -o s=` && [[ "$s" && "$s" != 'Z' ]]; do sleep 1; done
ps
, weder-p
oders=
unterstütztFreeBSD und Solaris haben dieses praktische
pwait(1)
Dienstprogramm, das genau das tut, was Sie wollen.Ich glaube, andere moderne Betriebssysteme haben auch die erforderlichen Systemaufrufe (MacOS implementiert beispielsweise BSDs
kqueue
), aber nicht alle stellen sie über die Befehlszeile zur Verfügung.quelle
> BSD and Solaris
: Inspektion der drei großen BSDs, die mir in den Sinn kommen; Weder OpenBSD noch NetBSD haben diese Funktion (in ihren Manpages), nur FreeBSD, wie Sie auf man.openbsd.org leicht überprüfen können .kqueue
, so dass das Kompilieren von FreeBSDspwait(1)
jedoch trivial wäre. Warum würde mir das Importieren der Funktion durch die anderen BSDs nicht entgehen ...plink me@oracle box -pw redacted "pwait 6998";email -b -s "It's done" etc
erlaubte mir nur, jetzt nach Hause zu gehen, anstatt in Stunden.Aus der Bash-Manpage
quelle
wait
Ohne Argumente wird der Prozess blockiert, bis alle untergeordneten Prozesse abgeschlossen sind. Ehrlich gesagt sehe ich keinen Grund, auf einen Prozess zu warten , da immer Systemprozesse stattfinden.sleep 1000
ctrl-z
wait [sleep pid]
kehrt sofort zurückAlle diese Lösungen werden in Ubuntu 14.04 getestet:
Lösung 1 (mit dem Befehl ps): Um die Antwort von Pierz zu addieren, würde ich vorschlagen:
grep -vw grep
Stellt in diesem Fall sicher, dass grep nur mit process_name und nicht mit grep selbst übereinstimmt. Es hat den Vorteil, dass Fälle unterstützt werden, in denen der Prozessname nicht am Ende einer Zeile bei stehtps axg
.Lösung 2 (unter Verwendung des Befehls top und des Prozessnamens):
Ersetzen Sie
process_name
durch den Prozessnamen, der in angezeigt wirdtop -n 1 -b
. Bitte halten Sie die Anführungszeichen.Um die Liste der Prozesse anzuzeigen, auf deren Abschluss Sie warten, können Sie Folgendes ausführen:
Lösung 3 (unter Verwendung des Befehls top und der Prozess-ID):
Ersetzen Sie
process_id
durch die Prozess-ID Ihres Programms.quelle
grep -v grep
Pipeline ist ein massives Gegenmuster, und dies setzt voraus, dass Sie keine nicht verwandten Prozesse mit demselben Namen haben. Wenn Sie stattdessen die PIDs kennen, kann dies an eine ordnungsgemäß funktionierende Lösung angepasst werden.-w
, um das Problemgrep -v grep
bis zu einem gewissen Grad zu vermeiden . Ich habe auch zwei weitere Lösungen hinzugefügt, die auf Ihrem Kommentar basieren.Okay, die Antwort scheint zu sein: Nein, es gibt kein eingebautes Tool.
Nach dem Einstellen
/proc/sys/kernel/yama/ptrace_scope
auf0
ist es möglich, dasstrace
Programm zu verwenden. Weitere Schalter können verwendet werden, um es leise zu machen, so dass es wirklich passiv wartet:quelle
Operation not permitted
für die zweite Strace-Instanz). Kannst du das bestätigen?(...)"tracee" always means "(one) thread"
(und ich bestätige den von Ihnen erwähnten Fehler). Damit mehr Prozesse auf diese Weise warten können, müssen Sie eine Kette erstellen.Blockierungslösung
Verwenden Sie die
wait
in einer Schleife, um darauf zu warten, dass alle Prozesse beendet werden:Diese Funktion wird sofort beendet, wenn alle Prozesse beendet wurden. Dies ist die effizienteste Lösung.
Nicht blockierende Lösung
Verwenden Sie die
kill -0
in einer Schleife, um auf das Beenden aller Prozesse zu warten und zwischen den Überprüfungen etwas zu tun:Die Reaktionszeit verkürzte sich auf die
sleep
Zeit, da eine hohe CPU-Auslastung verhindert werden muss.Eine realistische Verwendung:
Warten auf das Beenden aller Prozesse + Informieren Sie den Benutzer über alle laufenden PIDs.
Anmerkungen
Diese Funktionen erhalten PIDs über Argumente von
$@
als BASH-Array.quelle
Hatte das gleiche Problem, löste ich das Problem, indem ich den Prozess abbrach und dann darauf wartete, dass jeder Prozess mit dem PROC-Dateisystem beendet wurde:
quelle
Es gibt keine integrierte Funktion, die darauf warten kann, dass ein Prozess abgeschlossen wird.
Sie können
kill -0
an jede gefundene PID senden , damit Sie nicht von Zombies und Dingen verwirrt werden, die noch sichtbar sindps
(während Sie die PID-Liste mit abrufenps
).quelle
Verwenden Sie inotifywait, um eine Datei zu überwachen, die geschlossen wird, wenn Ihr Prozess beendet wird. Beispiel (unter Linux):
-e gibt das Ereignis an, auf das gewartet werden soll. -q bedeutet minimale Ausgabe nur bei Beendigung. In diesem Fall ist es:
Mit einem einzigen Wartebefehl können Sie auf mehrere Prozesse warten:
Die Ausgabezeichenfolge von inotifywait gibt an, welcher Prozess beendet wurde. Dies funktioniert nur mit 'echten' Dateien, nicht mit etwas in / proc /
quelle
Auf einem System wie OSX verfügen Sie möglicherweise nicht über pgrep, sodass Sie diesen Ansatz ausprobieren können, wenn Sie nach Prozessen mit Namen suchen:
Das
$
Symbol am Ende des Prozessnamens stellt sicher, dass grep nur process_name mit dem Zeilenende in der ps-Ausgabe und nicht mit sich selbst übereinstimmt.quelle
/dev/null
,-q
sollte mit verwendet werdengrep
. Eine andere Instanz des Prozesses hat möglicherweise begonnen, während Ihre Schleife geschlafen hat, und Sie werden es nie erfahren ...-q
Vorschlag gültig ist, stimmt, wie ich in meiner Antwort ausdrücklich erwähnt habe, das Abschlussmittel$
grep weder mit dem Namen "irgendwo in der Befehlszeile" noch mit sich selbst überein. Hast du es tatsächlich unter OSX versucht?Die Lösung von Rauno Palosaari für
Timeout in Seconds
Darwin
ist eine hervorragende Problemumgehung für ein UNIX-ähnliches Betriebssystem ohne GNUtail
(es ist nicht spezifisch fürDarwin
). Abhängig vom Alter des UNIX-ähnlichen Betriebssystems ist die angebotene Befehlszeile jedoch komplexer als erforderlich und kann fehlschlagen:Unter mindestens einem alten UNIX schlägt das
lsof
Argument+r 1m%s
fehl (auch für einen Superuser):Dies
m%s
ist eine Ausgabeformatspezifikation. Ein einfacher Postprozessor benötigt es nicht. Der folgende Befehl wartet beispielsweise bis zu fünf Sekunden auf PID 5959:In diesem Beispiel ist, wenn PID 5959 vor Ablauf der fünf Sekunden von selbst beendet
${?}
wird0
. Wenn nicht,${?}
kehrt1
nach fünf Sekunden zurück.Es lohnt sich ausdrücklich sein kann , dass die in der Feststellung
+r 1
, das1
ist das Abfrageintervall (in Sekunden), so dass es geändert werden kann , um die Situation zu entsprechen.quelle