Ich habe ein Bash-Skript, das einen untergeordneten Prozess startet, der von Zeit zu Zeit und ohne ersichtlichen Grund abstürzt (tatsächlich hängt) (Closed Source, daher kann ich nicht viel dagegen tun). Aus diesem Grund möchte ich diesen Prozess für eine bestimmte Zeit starten und beenden können, wenn er nach einer bestimmten Zeit nicht erfolgreich zurückgegeben wurde.
Gibt es eine einfache und robuste Möglichkeit, dies mit Bash zu erreichen?
PS: Sagen Sie mir, ob diese Frage besser für Serverfehler oder Superuser geeignet ist.
Antworten:
(Wie in: BASH FAQ-Eintrag Nr. 68 zu sehen: "Wie führe ich einen Befehl aus und lasse ihn nach N Sekunden abbrechen (Timeout)?" )
Wenn es Ihnen nichts ausmacht, etwas herunterzuladen, verwenden Sie
timeout
(sudo apt-get install timeout
) und verwenden Sie es wie folgt: (Die meisten Systeme haben es bereits installiert, andernfalls verwenden Siesudo apt-get install coreutils
)Wenn Sie etwas nicht herunterladen möchten, führen Sie das interne Timeout aus:
Wenn Sie eine Zeitüberschreitung für längeren Bash-Code durchführen möchten, verwenden Sie die zweite Option als solche:
quelle
cmdpid=$BASHPID
wird nicht die PID der aufrufenden Shell nehmen, sondern die (erste) Subshell, mit der begonnen wird()
. Das(sleep
Ding ... ruft eine zweite Unterschale innerhalb der ersten Unterschale auf, um 10 Sekunden im Hintergrund zu warten und die erste Unterschale zu töten, die nach dem Starten des Killer-Unterschalenprozesses ihre Arbeitslast ausführt ...timeout
ist Teil von GNU coreutils und sollte daher bereits in allen GNU-Systemen installiert sein.timeout
ist es jetzt Teil der Coreutils.oder um auch die Exit-Codes zu erhalten:
quelle
kill -9
bevor Sie Signale versuchen, die ein Prozess zuerst verarbeiten kann.dosmth
in 2 Sekunden beendet wird, ein anderer Prozess die alte PID übernimmt und Sie die neue töten?quelle
sleep 999
hier) oft schneller beendet wird als der auferlegte Schlaf (sleep 10
)? Was ist, wenn ich ihm eine Chance von bis zu 1 Minute, 5 Minuten geben möchte? Was ist, wenn ich eine Reihe solcher Fälle in meinem Skript habe :)Ich hatte auch diese Frage und fand zwei weitere Dinge sehr nützlich:
Also benutze ich so etwas in der Kommandozeile (OSX 10.9):
Da dies eine Schleife ist, habe ich "sleep 0.2" eingefügt, um die CPU kühl zu halten. ;-);
(Übrigens: Ping ist sowieso ein schlechtes Beispiel, Sie würden einfach die eingebaute Option "-t" (Timeout) verwenden.)
quelle
Angenommen, Sie haben eine PID-Datei (oder können diese leicht erstellen), um die PID des Kindes zu verfolgen, können Sie ein Skript erstellen, das die Modtime der PID-Datei überprüft und den Prozess nach Bedarf beendet / erneut startet. Dann legen Sie das Skript einfach in crontab ab, damit es ungefähr in dem von Ihnen benötigten Zeitraum ausgeführt wird.
Lassen Sie mich wissen, wenn Sie weitere Details benötigen. Wenn das nicht so klingt, als würde es Ihren Bedürfnissen entsprechen, was ist dann mit Emporkömmling?
quelle
Eine Möglichkeit besteht darin, das Programm in einer Subshell auszuführen und mit dem Befehl über eine Named Pipe mit der Subshell zu kommunizieren
read
. Auf diese Weise können Sie den Exit-Status des ausgeführten Prozesses überprüfen und diesen über die Pipe zurückmelden.Hier ist ein Beispiel für die Zeitüberschreitung des
yes
Befehls nach 3 Sekunden. Es erhält die PID des Prozesses mitpgrep
(funktioniert möglicherweise nur unter Linux). Es gibt auch ein Problem bei der Verwendung einer Pipe, da ein Prozess, der eine Pipe zum Lesen öffnet, hängen bleibt, bis sie auch zum Schreiben geöffnet wird, und umgekehrt. Um zu verhindern, dass derread
Befehl hängt, habe ich die Pipe zum Lesen mit einer Hintergrund-Subshell "eingeklemmt". (Eine andere Möglichkeit, ein Einfrieren zum Öffnen der Pipe mit Lese- und Schreibzugriff zu verhindern, dhread -t 5 <>finished.pipe
dies funktioniert möglicherweise auch nur unter Linux.)quelle
Hier ist ein Versuch, der versucht, das Beenden eines Prozesses zu vermeiden, nachdem er bereits beendet wurde, wodurch die Wahrscheinlichkeit verringert wird, dass ein anderer Prozess mit derselben Prozess-ID beendet wird (obwohl es wahrscheinlich unmöglich ist, diese Art von Fehler vollständig zu vermeiden).
Verwenden Sie like
run_with_timeout 3 sleep 10000
, das ausgeführt wird,sleep 10000
aber nach 3 Sekunden beendet wird.Dies ist wie bei anderen Antworten, bei denen ein Hintergrund-Timeout-Prozess verwendet wird, um den untergeordneten Prozess nach einer Verzögerung abzubrechen. Ich denke, dies entspricht fast der erweiterten Antwort von Dan ( https://stackoverflow.com/a/5161274/1351983 ), außer dass die Timeout-Shell nicht beendet wird, wenn sie bereits beendet ist.
Nach dem Ende dieses Programms werden noch einige "Schlaf" -Prozesse ausgeführt, die jedoch harmlos sein sollten.
Dies ist möglicherweise eine bessere Lösung als meine andere Antwort, da die nicht tragbare Shell-Funktion nicht verwendet wird
read -t
und nicht verwendet wirdpgrep
.quelle
(exec sh -c "$*") &
undsh -c "$*" &
? Warum sollte erstere anstelle der letzteren verwendet werden?Hier ist die dritte Antwort, die ich hier eingereicht habe. Dieser behandelt Signalunterbrechungen und bereinigt Hintergrundprozesse, wenn sie
SIGINT
empfangen werden. Es verwendet den in der oberen Antwort verwendeten Trick$BASHPID
und , um die PID eines Prozesses zu erhalten (in diesem Fall in einem Aufruf). Es verwendet ein FIFO, um mit einer Subshell zu kommunizieren, die für das Töten und Aufräumen verantwortlich ist. (Dies ist wie die Pipe in meiner zweiten Antwort , aber eine Named Pipe bedeutet, dass der Signalhandler auch in sie schreiben kann.)exec
$$
sh
Ich habe versucht, die Rennbedingungen so weit wie möglich zu vermeiden. Eine Fehlerquelle, die ich nicht beseitigen konnte, ist jedoch, wenn der Prozess fast zur gleichen Zeit wie das Zeitlimit endet. Zum Beispiel
run_with_timeout 2 sleep 2
oderrun_with_timeout 0 sleep 0
. Letzteres gibt für mich einen Fehler:da es versucht, einen Prozess zu beenden, der bereits von selbst beendet wurde.
quelle