timeout-Befehl in Bash
Dieser Artikel ist eine einfache Anleitung zum Einrichten eines Timeouts für bestimmte Programme mit dem Befehl timeout
des GNU-Pakets coreutils
in Bash.
der timeout
-Befehl in Bash
In vielen Situationen, z. B. beim Abrufen von Daten von einem Server oder beim Ausführen einer Funktion oder eines Programms mit zufälligen Eingaben, kann das Programm oder die Funktion sehr lange oder unbegrenzt ausgeführt werden.
In solchen Fällen ist es wichtig, das Programm zu stoppen und zu verhindern, dass mehr Zeit und Ressourcen verschwendet werden.
Hier kommt eine Timeout-Funktionalität ins Spiel. Der Benutzer definiert ein Zeitlimit, und dann darf das Programm bis zum erfolgreichen Abschluss ausgeführt werden, und wenn es bis zum benutzerdefinierten Zeitlimit zu lange dauert, wird es beendet.
Die Timeout-Funktionalität ist normalerweise für die meisten Programmiersprachen integriert. Für Bash ist es jedoch nicht integriert und Teil eines externen Pakets namens coreutils
.
Dieses Paket wird von GNU entwickelt und gepflegt und enthält Implementierungen vieler grundlegender Dienstprogramme.
Das Paket coreutils
kann einfach durch Ausführen des Befehls sudo apt-get install -y coreutils
in LINUX-Systemen installiert werden.
Um die coreutils
auf macOS-Systemen zu erhalten, müssen Sie zuerst Homebrew installiert haben. Um Homebrew zu erhalten, führen Sie den folgenden Befehl im Befehlsterminal aus.
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Führen Sie nach der vollständigen Installation von Homebrew den folgenden Befehl aus.
brew install coreutils
coreutils
-Befehle auf macOS haben alle Befehle ein g
vor dem Namen (z. B. gdir
oder gtimeout
).Wenn Sie das Paket coreutils
installiert haben, können Sie einfach die Funktion timeout
verwenden, zum Beispiel:
timeout 10 ping google.com
Der obige Befehl gibt aus:
Das Dienstprogramm ping
in Bash ist integriert und läuft weiter, bis es manuell unterbrochen wird. Standardmäßig sendet ping
alle 1 Sekunde ein Paket.
Wie oben zu sehen, beendet der Befehl timeout
ping
nach 10 Sekunden, da die Zahl direkt nach dem Befehl timeout
das Zeitlimit ist.
Daher bedeutet der Befehl timeout 10 cmd1
, dass cmd1
bis zum erfolgreichen Abschluss oder 10 Sekunden ausgeführt wird, je nachdem, was früher eintritt. Die Zeiteinheit für den timeout
-Befehl ist in Sekunden.
Um einen in Minuten, Stunden oder Tagen gemessenen Zeitwert zu verwenden, fügen Sie jeweils ein m
, ein h
oder ein d
hinzu.
So stellen Sie beispielsweise ein Timeout von 2 Minuten ein:
timeout 2m programToRun
Es ist zu beachten, dass der Exit-Status für ein Timeout 124
ist, wenn der Prozess abläuft. Im folgenden Beispiel verwenden wir dies, um zu überprüfen, ob der Prozess abgelaufen ist oder nicht.
timeout 1 ping 8.8.8.8 -w3
EXIT_STATUS=$?
if [ $EXIT_STATUS -eq 124 ]
then
echo 'Process timed out!'
else
echo 'Process did not timeout.'
fi
exit $EXIT_STATUS
Wenn der Vorgang im oben dargestellten Beispiel nicht innerhalb von 1 Sekunde abgeschlossen ist, wird der Vorgang abgebrochen. Die Erweiterung -w3
zeigt an, dass die Adresse dreimal angepingt wird.
Daher läuft dieser Prozess immer ab und gibt die folgende Ausgabe aus.
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=57 time=40.4 ms
Process timed out!
Es ist wichtig zu beachten, dass ein interner Timeout auch zum gleichen Exit-Status (124
) führt. Daher zeigt diese Ausgabe an, dass entweder der Prozess mit unserem angegebenen Timeout abgelaufen ist oder ein interner Timeout ihn beendet hat.
Verwenden Sie timeout
mit SIGKILL
Signal in Bash
Typischerweise sendet die timeout
-Funktion ein SIGTERM
-Signal, um die Ausführung eines Programms zu stoppen, wenn das Zeitlimit erreicht ist. Das Problem ist, dass manche Programme das SIGTERM
-Signal ignorieren und weiterlaufen.
Hier kommt das SIGKILL
-Signal ins Spiel; Es stoppt sofort die Ausführung eines Prozesses und aller seiner untergeordneten Prozesse und kann nicht blockiert oder ignoriert werden. Um ein Timeout mit SIGKILL
zu verwenden, müssen wir das Flag -s
hinzufügen.
Zum Beispiel:
timeout -s SIGKILL 10 programToRun
Wenn timeout
nicht direkt von der Shell ausgeführt wird, wie beim Ausführen von einem Skript, ist es wichtig, --foreground
zum timeout
-Befehl hinzuzufügen.
Es können viele Alternativen zum timeout
-Befehl verwendet werden, die alle hauptsächlich auf der gleichen Logik basieren, ein Kill-Signal mit sleep
zu verwenden und dann den erforderlichen Befehl oder das Programm auszuführen, das gestoppt wird, sobald sleep
endet.
Beispiel:
(sleep 2 && killall prog) & ./prog
Der obige Code beendet alle Prozesse von prog
nach 2 Sekunden, wenn prog
seine Ausführung nicht abgeschlossen hat. Solche Lösungen können funktionieren, sind aber nicht so sicher und zuverlässig wie der Befehl timeout
, daher ist es immer besser, stattdessen timeout
zu verwenden.