Hinweis Ein einfältiger Einzeiler mit kill 0, $pid
ist am Ende, kommentiert.
Wir müssen den Abschluss eines externen Programms erkennen, das von diesem Skript nicht gestartet wurde. Die Frage fragt nach der Verwendung von waitpid
. Um meinen frühen Kommentar zu kopieren:
Sie können nicht. Sie können nur auf einen Kindprozess warten. Siehe perldoc wait
(oder waitpid
, es ist das gleiche), erster Satz.
Die wait
und waitpid
Warten auf Signale an das Skript über das Schicksal seines Kind geboren (ern). Es gibt keinen Grund dafür, dass das Skript solche Signale über Prozesse empfängt, die nicht gestartet wurden.
Wir kennen die ID des Prozesses und seinen Namen.Seine PID kann verwendet werden, um Abfrage für, ob es ausgeführt wird. Die Verwendung von pid
alleine ist nicht vollständig zuverlässig, da zwischen unseren Prüfungen der Prozess beendet werden kann und ein zufälliger neuer derselben pid
zugewiesen werden kann. Wir können den Namen des Programms verwenden, um dies zu verstärken.
Auf einem Linux-System können Informationen über einen Prozess abgerufen werden, indem (viele) ps
Optionen verwendet werden. Jede dieser kehrt das Programm zum vollständigen Aufruf
ps --no-headers -o cmd PID
ps --no-headers -p PID -o cmd
Der zurückgegebene String kann mit dem Dolmetscher Pfad starten (für ein Perl-Skript, zum Beispiel), gefolgt von dem vollständigen Namen des Programms. Die Version ps -p PID -o comm=
gibt nur den Namen des Programms zurück, aber ich finde, dass es dieses Wort an einem Bindestrich (wenn dort) brechen kann, was zu einem unvollständigen Namen führt. Dies kann bei einigen Systemen eine Feinabstimmung erfordern, konsultieren Sie bitte Ihre . Wenn es keinen Prozess mit gegebener PID gibt, bekommen wir nichts zurück.
Dann können wir auf PID überprüfen und wenn gefunden, überprüfen, ob der Name für diese PID mit dem Programm übereinstimmt. Der Name des Programms ist bekannt und wir könnten das nur hart codieren. Es wird jedoch immer noch vom Skript beim Starten unter Verwendung des obigen Befehls ps
erhalten, um Mehrdeutigkeiten zu vermeiden. (Dann ist es auch im gleichen Format für späteren Vergleich.) Dies selbst wird gegen den bekannten Namen überprüft, da es keine Garantie gibt, dass die PID zum Zeitpunkt der Skriptausführung tatsächlich für das erwartete Programm ist.
use warnings;
use strict;
# For testing. Retrieve your PID as appropriate for real use
my $ext_pid = $ARGV[0] || $$;
my $cmd_get_name = "ps --no-headers -o cmd $ext_pid";
# For testing. Replace 'sleep' by your program name for real use
my $known_prog_name = 'sleep';
# Get the name of the program with PID
my $prog_name = qx($cmd_get_name);
# Test against the known name, exit if there is a mismatch
if ($prog_name !~ $known_prog_name) {
warn "Mismatch between:\n$prog_name\n$known_prog_name -- $!";
exit;
}
my $name;
while ($name = qx($cmd_get_name) and $name =~ /$prog_name/)
{
print "Sleeping 1 sec ... \n";
sleep 1;
}
# regex above may need slight adjustment, depending on format of ps return
Die Befehlsausgabe, empfangen über qx()
oben (Graviszeichen Operator) eine neue Zeile enthält. Wenn sich herausstellt, dass das Skript ein Problem darstellt, kann es chomp
-ed sein, was eine leichte Anpassung erfordern würde. Die verbleibende Lücke ist, dass , dass sehr Programm möglicherweise beendet wurde und wurde zwischen den Prüfungen und mit der gleichen PID neu gestartet.
Dies würde durch Laufen in einer Schale
sleep 30 &
script.pl `ps aux | egrep '[s]leep'`
Die egrep
grep -E
ist getestet werden. Die Ausgabe von `ps ...`
enthält mehrere Wörter. Diese werden als Befehlszeilenargumente an unser Skript übergeben, das die erste als PID verwendet. Wenn es ein Problem damit gibt, führen Sie zuerst die Filterung ps
durch und geben Sie dann die PID als Eingabeargument des Skripts manuell ein. Die sleep
von 30 Sekunden oben soll genug Zeit geben, das alles auf der Kommandozeile zu tun.
Der Code kann vereinfacht werden, indem $name
mit einem hartcodierten $prog_name
verglichen wird, wenn der Programmname eindeutig genug ist und sich nicht ändert. Der hartcodierte Name ist oben verwendet, aber für eine Überprüfung und es generiert eine Warnung, wenn nicht übereinstimmte. (Wenn wir auf sie verlassen nur hartkodierte können wir Warnungen nicht ausgeben, wenn es nicht übereinstimmt, denn das ist dann ein Teil des Codes der Operation.)
Wenn der Prozess durch den gleichen Benutzer wie das Skript gehört ein kill 0, $pid
verwenden können als
while (kill 0, $ext_pid) { sleep 1 }
Dann würden Sie entweder einen weiteren Anruf zu machen, den Namen zu überprüfen oder mit dem (kleinen) Möglichkeit eines Fehlers zufrieden sein, in welchem tatsächlichen Prozess der $pid
darstellt.
Das Modul Proc::ProcessTable
kann stattdessen für alle diese verwendet werden. Auf einem Windows-System wäre dies der richtige Weg.
Sind Sie sicher, dass $ pid das ist, was Sie denken, dass es ist? Was ist der Rückgabewert von 'waitpid'? Es zeigt an, welcher Prozess beendet wurde. – Schwern
@Schwern - Rückgabewert von waitpid ist -1. Dies bedeutet, dass es keinen solchen Kindprozess gibt, denke ich. Und ich habe unten Zeilen hinzugefügt, um zu überprüfen, ob $ pid läuft oder nicht. mein $ exists = kill 0, $ pid; print "Prozess läuft \ n" if ($ exists); Und es druckt die Aussage – user3395103
Sie können nicht. Sie können nur auf einen Child-Prozess warten. Siehe 'perldoc wait' (oder' waitpid', es ist das gleiche), erster Satz. Wenn Sie wissen wollen, wann ein externes Programm abgeschlossen ist, müssen Sie ganz andere Dinge tun. – zdim