Wie kann ein Programm abgebrochen werden, wenn es in einem bestimmten Timeout keine Ausgabe erzeugt hat?

391
Yajo

Ich möchte erkennen, wenn ein Prozess stecken bleibt, aber ich bekomme keine Hinweise auf die Angelegenheit. Ich weiß nur, wenn es in einem bestimmten Timeout (z. B. 30 Sekunden) keine Ausgabe erzeugt, bedeutet dies, dass es wahrscheinlich blockiert ist.

Ich kenne das timeoutProgramm von coreutils, aber es basiert auf der vollen Programmbeendigungszeit und nicht auf der letzten Zeile der Ausgabezeit. Ich würde lieben, wenn so etwas funktioniert:

timeout --stdout --stderr 30s my-program 

Gibt es eine Möglichkeit, dies zu tun? Wie kann ich es tun?

2
Die Idee gefällt mir, aber ich kann nicht auf ein vorhandenes Werkzeug verweisen. Dies sollte an sich nicht schwer sein. tripleee vor 6 Jahren 0
Möglicherweise ist [this] (https://spin.atomicobject.com/2016/12/08/monitoring-stdout-with-a-timeout/) hilfreich. Wobbly vor 6 Jahren 0

3 Antworten auf die Frage

1
Kamil Maciorowski

Der Code

Speichern Sie dies als tkill(machen Sie es ausführbar und passen Sie es PATHggf. an):

#!/bin/bash  _terminate_children() { trap "exit 143" SIGTERM && kill -- -$$ }  trap _terminate_children SIGINT SIGTERM  tout="$1" shift eval $@ | tee >(while :; do read -t "$tout" case $? in 0) : ;; 1) break ;; *) _terminate_children ;; esac done) exit $ 

Grundlegende Verwendung

tkill 30 some_command 

Das erste Argument ( 30hier) ist das Timeout in Sekunden.


Anmerkungen

  • tkillerwartet some_commandeine Textausgabe (nicht binär).
  • tkillSonden stdoutdes gegebenen Befehls. Um auch stderrumleiten es wie im letzten fortgeschrittenen Beispiel unten.

Erweiterte Nutzung

Dies sind gültige Beispiele:

tkill 9 foo -option value tkill 9 "foo -option value" # equivalent to the above tkill 5 "foo | bar" tkill 5 'foo | bar' tkill 5 'foo | bar | baz' # tkill monitors baz tkill 5 'foo | bar' | baz # baz reads from tkill tkill 3 "foo; bar" tkill 6 "foo && bar || baz" tkill 7 "some_command 2>&1" 

Verwenden Sie die Bash-Syntax in diesen Anführungszeichen.


Status beenden

  • Wenn some_commandExits von selbst beendet werden, wird der Exitstatus als Exitstatus von verwendet tkill. tkill 5 truekehrt zurück 0; tkill 5 falsekehrt zurück 1; tkill 5 "true; false"kehrt zurück 1.
  • Wenn das angegebene Timeout abläuft oder tkillunterbrochen wird SIGINToder SIGTERMder Exit-Status lautet, wird der Exit-Status angezeigt 143.

Code-Fragmente erklärt

  • eval macht die fortgeschrittenen Beispiele möglich.
  • teeerlaubt uns zu analysieren, stdinwährend wir noch eine Kopie davon übergeben stdout.
  • read -t Ist für die Anwendung des Timeouts verantwortlich, wird anhand seines Exit-Status festgelegt, was als Nächstes zu tun ist.
  • Überwachte Befehle werden bei dieser Lösung abgebrochen, wenn dies erforderlich ist .
  • Der Beendigungsstatus der überwachten Befehle wird mit dieser Lösung abgerufen .
0
Ljm Dullaart

Also im Grunde so etwas:

#!/bin/bash tmp1=/tmp/tmp-$$-1 tmp2=/tmp/tmp-$$-2 touch $tmp1 touch $tmp2  time_out=30  typeset -i i  i=0 my-program > $tmp1 & pgmpid=$!  while ps $pgmpid > /dev/null ; do sleep 1 if diff $tmp1 $tmp2 > /dev/null ; then i=i+1 if [ $i -gt $time_out ] ; then kill $pgmpid fi else i=0 cp $tmp1 $tmp2  fi done  rm -f $tmp1 $tmp2 
Dies sollte den Trick tun, obwohl ich mit einer Art Ein-Liner-TBH gerechnet hatte ... Trotzdem danke! Yajo vor 6 Jahren 0
0
Lubo Kanev

Führen Sie das Programm im Hintergrund aus, während Sie die Ausgabe in eine Datei kopieren. Wenn die Datei nach 30 Sekunden leer ist, beenden Sie das Programm, oder bringen Sie es in den Vordergrund.

my-program | tee temp-file &  sleep 30 [ -s temp-file ] && kill $! || fg $! 
Wenn dies nach 30 Sekunden eingefroren ist, haben Sie kein Glück mehr, oder? Yajo vor 6 Jahren 0
Ja. Anscheinend habe ich die Frage missverstanden. Lubo Kanev vor 6 Jahren 0