Diese Antwort auf den Befehlszeilenbefehl zum automatischen Beenden eines Befehls nach einer bestimmten Zeit
schlägt eine 1-zeilige Methode vor, um einen Befehl mit langer Laufzeit über die Bash-Befehlszeile zu deaktivieren:
( /path/to/slow command with options ) & sleep 5 ; kill $!
Es ist jedoch möglich, dass ein bestimmter "lang laufender" Befehl vor dem Timeout beendet wird. (Nennen wir es einen "normalerweise lang laufenden, aber manchmal schnellen" Befehl oder tlrbsf zum Spaß.)
Dieser raffinierte 1-Liner-Ansatz hat also einige Probleme. Erstens ist das sleep
nicht bedingt, so dass eine unerwünschte Untergrenze für die Zeit festgelegt wird, die für den Abschluss der Sequenz benötigt wird. Betrachten Sie 30s oder 2m oder sogar 5m für den Schlaf, wenn der Befehl tlrbsf in 2 Sekunden beendet ist - höchst unerwünscht. Zweitens ist das kill
unbedingt erforderlich, sodass diese Sequenz versucht, einen nicht laufenden Prozess zu beenden und darüber zu jammern.
So...
Gibt es eine Möglichkeit , einen normalerweise lang laufenden, aber manchmal schnellen Befehl ( "tlrbsf" ) zu umgehen?
- hat eine Bash-Implementierung (die andere Frage hat bereits Perl- und C-Antworten)
- wird am früheren der beiden beendet: tlrbsf- Programmbeendigung oder abgelaufenes Timeout
- tötet nicht vorhandene / nicht laufende Prozesse nicht ab (oder beschwert sich optional nicht über einen schlechten Kill)
- muss kein 1-Liner sein
- kann unter Cygwin oder Linux laufen
... und führt für Bonuspunkte den Befehl tlrbsf im Vordergrund und einen beliebigen "Schlaf" - oder zusätzlichen Prozess im Hintergrund aus, sodass der Befehl stdin / stdout / stderr des Befehls tlrbsf wie zuvor umgeleitet werden kann direkt laufen?
Wenn ja, teilen Sie bitte Ihren Code. Wenn nicht, erklären Sie bitte warum.
Ich habe eine Weile versucht, das oben genannte Beispiel zu hacken, aber ich stoße an die Grenze meiner Bash-Fähigkeiten.
quelle
timeout
Dienstprogramm gnu nicht zu verwenden ?timeout
ist toll! Sie können sogar mehrere Befehle verwenden (mehrzeiliges Skript): stackoverflow.com/a/61888916/658497Antworten:
Ich denke, genau darum bitten Sie:
http://www.bashcookbook.com/bashinfo/source/bash-4.0/examples/scripts/timeout3
quelle
Sie suchen wahrscheinlich nach dem
timeout
Befehl in coreutils. Da es ein Teil von Coreutils ist, ist es technisch gesehen eine C-Lösung, aber es sind immer noch Coreutils.info timeout
für mehr Details. Hier ist ein Beispiel:quelle
gtimeout
brew install coreutils
, und Sie können ihn dann verwendengtimeout
.Diese Lösung funktioniert unabhängig vom Bash-Monitor-Modus. Sie können das richtige Signal verwenden, um Ihren Befehl zu beenden
Der Beobachter beendet Ihren Befehl nach einer bestimmten Zeitüberschreitung. Das Skript wartet auf die langsame Aufgabe und beendet den Watcher. Beachten Sie, dass
wait
dies nicht mit Prozessen funktioniert, die untergeordnete Elemente einer anderen Shell sind.Beispiele:
quelle
wait
Gibt den Exit-Status des Prozesses zurück, auf den gewartet wird. Wenn Ihr Befehl also innerhalb der zugewiesenen Zeit, jedoch mit einem Exit-Status ungleich Null, beendet wird, verhält sich die Logik hier so, wie sie abgelaufen ist, dh gedrucktyour_command interrupted
. Stattdessen können Sie auf daswait
verzichtenif
und dann überprüfen, ob die$watcher
PID noch vorhanden ist. Wenn dies der Fall ist, wissen Sie, dass Sie kein Timeout durchgeführt haben.kill
in einem Fall verwendet wird, aberpkill
in dem anderen. Ich musstepkill
für beide verwenden, damit dies richtig funktioniert. Ich würde erwarten, dass Sie einen Befehl()
verwenden müssenpkill
, um ihn zu beenden, wenn Sie ihn einschließen . Aber vielleicht funktioniert es anders, wenn es nur einen einzigen Befehl innerhalb der gibt()
.Los geht's:
du kannst das
SIGINT
und10
wie du willst ändern ;)quelle
coreutils
Paket auf FreeBSD enthalten.Sie können dies vollständig mit
bash 4.3
und über tun :_timeout 5 longrunning_command args
{ _timeout 5 producer || echo KABOOM $?; } | consumer
producer | { _timeout 5 consumer1; consumer2; }
Beispiel:
{ while date; do sleep .3; done; } | _timeout 5 cat | less
Benötigt Bash 4.3 für
wait -n
Wenn Sie den Rückkehrcode nicht benötigen, kann dies noch einfacher gemacht werden:
Anmerkungen:
Genau genommen brauchen Sie das
;
In nicht; )
, aber es macht die Sache konsistenter mit dem; }
Fall. Und dasset +b
kann man wahrscheinlich auch weglassen, aber besser sicher als leid.Mit Ausnahme
--forground
(wahrscheinlich) können Sie alle Variantentimeout
unterstützen.--preserve-status
ist allerdings etwas schwierig. Dies bleibt als Übung für den Leser;)Dieses Rezept kann "natürlich" in der Schale verwendet werden (so natürlich wie für
flock fd
):Wie oben erläutert, können Sie Umgebungsvariablen auf diese Weise natürlich nicht erneut in die umschließende Shell exportieren.
Bearbeiten:
Beispiel aus der
__git_ps1
Praxis : Auszeit für den Fall, dass es zu lange dauert (für Dinge wie langsame SSHFS-Links):Edit2: Bugfix. Mir ist aufgefallen, dass
exit 137
das nicht benötigt wird und gleichzeitig_timeout
unzuverlässig macht .Edit3:
git
ist ein eingefleischter, daher braucht es einen doppelten Trick, um zufriedenstellend zu arbeiten.Edit4: Ich habe ein
_
erstes_timeout
GIT-Beispiel für die reale Welt vergessen .quelle
cc. The 'wait' builtin has a new '-n' option to wait for the next child to change status.
Von: tiswww.case.edu/php/chet/bash/NEWSIch bevorzuge "timelimit", das ein Paket zumindest in Debian hat.
http://devel.ringlet.net/sysutils/timelimit/
Es ist ein bisschen schöner als das "Timeout" der Coreutils, da es beim Beenden des Prozesses etwas druckt und nach einiger Zeit standardmäßig auch SIGKILL sendet.
quelle
timelimit -t1 ./a_forking_prog
nur einen der beiden Prozesse beenden ), aber Timeout funktioniert.Zeitüberschreitung
slowcommand
nach 1 Sekunde:timeout 1 slowcommand || echo "I failed, perhaps due to time out"
Überprüfen Sie, ob der Statuscode 124 lautet, um festzustellen, ob der Befehl aus eigenen Gründen abgelaufen ist oder fehlgeschlagen ist:
Beachten Sie, dass Sie bei einem Exit-Status von 124 nicht wissen
timeout
, ob das Zeitlimit aufgrund Ihres Befehls abgelaufen ist oder ob der Befehl selbst aufgrund einer eigenen internen Zeitüberschreitungslogik beendet und dann zurückgegeben wurde 124. Sie können in beiden Fällen sicher davon ausgehen Es kam jedoch zu einer Auszeit.quelle
Siehe auch das Skript http://www.pixelbeat.org/scripts/timeout, dessen Funktionalität in neuere Coreutils integriert wurde
quelle
Ein bisschen hacky, aber es funktioniert. Funktioniert nicht, wenn Sie andere Vordergrundprozesse haben (bitte helfen Sie mir, dies zu beheben!)
Eigentlich denke ich, dass Sie es umkehren können, indem Sie Ihre Bonuskriterien erfüllen:
quelle
Timeout ist wahrscheinlich der erste Ansatz. Möglicherweise müssen Sie eine Benachrichtigung oder einen anderen Befehl ausführen, wenn das Zeitlimit überschritten wird. Nach einigem Suchen und Experimentieren habe ich mir dieses Bash- Skript ausgedacht :
quelle
Einfaches Skript mit Codeklarheit. Speichern unter
/usr/local/bin/run
:Zeitüberschreitung eines zu langen Befehls:
Beendet sofort für einen Befehl, der ausgeführt wird:
quelle
Wenn Sie bereits den Namen des Programms kennen (nehmen wir an
program
), das nach dem Timeout beendet werden soll (als Beispiel3
Sekunden), kann ich eine einfache und etwas schmutzige alternative Lösung beisteuern:Dies funktioniert perfekt, wenn ich Benchmark-Prozesse mit Systemaufrufen aufrufe.
quelle
argv[0]
, möglicherweise mit anderen Hacks, um mehr Platz zu schaffen).(sleep 3 && docker stop <container>) &
gut funktioniert , dem Container einen Namen zu geben und ihn zu verwenden . Vielen Dank!{ sleep 5 && kill -9 $(ps -fe | grep "program" | grep $$ | tr -s " " | cut -d" " -f2); } & SLEEPPID=$!; bash -c "program" && kill -9 $SLEEPPID"
folgt verbessert werden: Auf diese Weise werden nur Jobs in der aktuellen Shell beendet.Es gibt auch
cratimeout
von Martin Cracauer (geschrieben in C für Unix- und Linux-Systeme).quelle
OS X verwendet Bash 4 noch nicht und verfügt auch nicht über / usr / bin / timeout. Daher ist hier eine Funktion, die unter OS X ohne Home-Brew oder Macports funktioniert, die / usr / bin / timeout (basierend auf Tino's) ähnelt Antworten). Die Validierung, Hilfe, Verwendung und Unterstützung von Parametern für andere Signale ist eine Übung für den Leser.
quelle
In 99% der Fälle besteht die Antwort darin, KEINE Timeout-Logik zu implementieren. Timeout-Logik ist in fast jeder Situation ein rotes Warnsignal dafür, dass etwas anderes nicht stimmt und stattdessen behoben werden sollte .
Hängt oder bricht Ihr Prozess manchmal nach n Sekunden? Dann finden Sie heraus warum und beheben Sie das stattdessen.
Abgesehen davon, um die Lösung von strager richtig zu machen, müssen Sie wait "$ SPID" anstelle von fg 1 verwenden, da Sie in Skripten keine Jobsteuerung haben (und der Versuch, sie einzuschalten, dumm ist). Darüber hinaus beruht fg 1 auf der Tatsache, dass Sie zuvor keine anderen Jobs im Skript gestartet haben, was eine schlechte Annahme ist.
quelle
Mir wurde ein Problem beim Beibehalten des Shell-Kontexts und beim Zulassen von Zeitüberschreitungen angezeigt. Das einzige Problem dabei ist, dass die Skriptausführung bei der Zeitüberschreitung gestoppt wird - aber es entspricht den Anforderungen, die mir gestellt wurden:
mit den Ausgängen:
Natürlich nehme ich an, dass es ein Verzeichnis namens gab
scripts
quelle
quelle
Mein Problem war vielleicht etwas anders: Ich starte einen Befehl über ssh auf einem Remotecomputer und möchte die Shell und die Kinder töten, wenn der Befehl hängt.
Ich benutze jetzt folgendes:
Auf diese Weise gibt der Befehl 255 zurück, wenn eine Zeitüberschreitung aufgetreten ist, oder den Rückkehrcode des Befehls bei Erfolg
Bitte beachten Sie, dass das Beenden von Prozessen aus einer SSH-Sitzung anders gehandhabt wird als eine interaktive Shell. Sie können aber auch die Option -t für ssh verwenden, um ein Pseudo-Terminal zuzuweisen, sodass es sich wie eine interaktive Shell verhält
quelle
Hier ist eine Version, die nicht auf dem Laichen eines untergeordneten Prozesses beruht. Ich benötigte ein eigenständiges Skript, in das diese Funktionalität eingebettet war. Es wird auch ein gebrochenes Abfrageintervall durchgeführt, sodass Sie schneller abrufen können. Timeout wäre bevorzugt gewesen - aber ich stecke auf einem alten Server fest
quelle
Ein sehr vereinfachter Weg:
Mit pkill (Option -f ) können Sie Ihren spezifischen Befehl mit Argumenten beenden oder -n angeben, um zu vermeiden, dass alte Prozesse beendet werden.
quelle
Aufbauend auf der Antwort von @ loup ...
Wenn Sie ein Zeitlimit für einen Prozess festlegen und die Ausgabe von Kill Job / PID stummschalten möchten, führen Sie Folgendes aus:
Dadurch wird der Hintergrundprozess in eine Unterschale eingefügt, sodass die Jobausgabe nicht angezeigt wird.
quelle
Ich habe einen Cron-Job, der ein PHP-Skript aufruft und manchmal im PHP-Skript hängen bleibt. Diese Lösung war perfekt für mich.
Ich benutze:
quelle
scripttimeout
?