Beobachten Sie die Ausgabe eines Befehls, bis eine bestimmte Zeichenfolge beobachtet wird, und beenden Sie sie dann

29

Ich suche nach einer Möglichkeit, die Ausgabe eines Befehls programmgesteuert zu überwachen, bis eine bestimmte Zeichenfolge beobachtet wird, und dann zu beenden. Dies ist dieser Frage sehr ähnlich , aber anstatt eine Datei zu verfolgen, möchte ich einen Befehl verfolgen.

So etwas wie:

watch -n1 my_cmd | grep -m 1 "String auf der Suche nach"

(Aber das funktioniert bei mir nicht.)

UPDATE: Ich muss klarstellen, dass 'my_cmd' keinen fortlaufenden Text ausgibt, sondern wiederholt aufgerufen werden muss, bis die Zeichenfolge gefunden wurde (weshalb ich an den Befehl 'watch' dachte). In dieser Hinsicht ähnelt 'my_cmd' vielen anderen Unix-Befehlen wie: ps, ls, lsof, last usw.

gdw2
quelle
Ich hätte gedacht, es wäre möglich, tail -fein Programm genauso wie eine Datei auszugeben ... irre ich mich?
Joanis
@Joanis. Sie haben Recht, aber in meinem Fall erzeugt 'my_cmd' keine kontinuierliche Ausgabe und muss wiederholt aufgerufen werden (ähnlich wie bei den meisten Befehlen: ps, ls, lsof usw.)
gdw2

Antworten:

41

Benutze eine Schleife:

until my_cmd | grep -m 1 "String Im Looking For"; do : ; done

Stattdessen :können Sie sleep 1(oder 0.2) verwenden, um die CPU zu entlasten.

Die Schleife wird ausgeführt, bis grep die Zeichenfolge in der Ausgabe des Befehls findet. -m 1bedeutet "eine Übereinstimmung ist genug", dh grep stoppt die Suche, nachdem es die erste Übereinstimmung gefunden hat.

Sie können auch verwenden, grep -qwas auch beendet wird, nachdem Sie die erste Übereinstimmung gefunden haben, ohne jedoch die übereinstimmende Zeile auszudrucken.

Choroba
quelle
Eine Erklärung dieses Befehls wäre wünschenswert.
Mark W
@ MarkW: Aktualisiert.
Choroba
jemand anderes erwähnte, grep -qwas eine andere Option ist. grep wird beendet, nachdem der String gefunden wurde.
So,
Beachten Sie, dass dieser Befehl den betreffenden Befehl wiederholt ausführt, was möglicherweise wünschenswert oder nicht wünschenswert ist.
Adrien
1
@A__: Es ist wünschenswert, wie im OP unter "Update" angegeben.
choroba
11
watch -e "! my_cmd | grep -m 1 \"String Im Looking For\""
  • ! negiert den Exit-Code der Befehlspipeline
  • grep -m 1 Wird beendet, wenn eine Zeichenfolge gefunden wird
  • watch -e Gibt zurück, wenn ein Fehler aufgetreten ist

Dies kann jedoch verbessert werden, um tatsächlich die übereinstimmende Linie anzuzeigen, die bisher weggeworfen wurde.

Mathematik
quelle
Danke für die ausführliche Erklärung, aber bei mir funktioniert es nicht. Mein watchBefehl (CentOS) hat keine -eFlagge (was eigentlich keine Rolle spielen sollte). Noch wichtiger ist jedoch, dass die Überwachung nach dem Auffinden der Zeichenfolge weiterläuft und nicht beendet wird. Es scheint, dass wenn es beendet wird grep -m, es nur tötet my_cmd, aber nicht beendet wird watch.
gdw2
Nein, ist egal !, das Flag "-e" dient zum Verlassen der Überwachung, wenn der Befehl einen anderen Fehlercode als 0 aufweist. Da die nicht vorhandene Überwachung auf Ihrer Plattform fortgesetzt wird. Wie auch immer, gut zu wissen, auf meiner Ubuntu 11.10-Installation ist alles in Ordnung. Ich habe auch manchmal Probleme mit Mac OS X bezüglich sehr veralteter Kommandozeilen-Tools, und ich verwende bisher Mac-Ports, um mehr aktuelle Software zu erhalten.
Mathe
Dadurch wird verhindert , wenn das Muster gefunden wird, aber es zeigt keine Ausgabe , bis das passiert
Mark
Sie können teedafür anstellen, aber dies führt zu einem irreführenden Zeilenumbruch. Ich weiß momentan nicht, wie ich das umgehen soll:watch -n1 -e "! date | tee /dev/tty | grep --color -m 1 \"17\""
Mathe
Ja, das hat bei mir nicht funktioniert. watchhört pflichtbewusst auf zu schauen, wenn die Zeichenfolge gefunden wird, wird jedoch erst beendet, wenn Sie eine Taste drücken. So nah.
mlissner
8

Für diejenigen, die ein Programm haben, das kontinuierlich nach stdout schreibt, ist alles, was Sie tun müssen, es an grep mit der Option 'single match' weiterzuleiten. Sobald grep die passende Zeichenfolge gefunden hat, wird es beendet, wodurch stdout für den Prozess geschlossen wird, der an grep weitergeleitet wird. Dieses Ereignis sollte natürlich dazu führen, dass das Programm ordnungsgemäß beendet wird , solange der Prozess erneut schreibt .

Was passieren wird, ist, dass der Prozess ein SIGPIPE erhält, wenn er versucht, nach dem Beenden von grep auf closed stdout zu schreiben. Hier ist ein Beispiel mit Ping, das andernfalls auf unbestimmte Zeit ausgeführt würde:

$ ping superuser.com | grep -m 1 "icmp_seq"

Dieser Befehl stimmt mit dem ersten erfolgreichen 'pong' überein und wird dann beendet, wenn das nächste Mal pingversucht wird, nach stdout zu schreiben.


Jedoch,

Es ist nicht immer garantiert, dass der Prozess wieder auf stdout schreibt und daher möglicherweise kein SIGPIPE ausgelöst wird (dies kann z. B. beim Verfolgen einer Protokolldatei passieren). Die beste Lösung für dieses Szenario ist das Schreiben in eine Datei. Bitte kommentieren Sie, wenn Sie glauben, dass Sie sich verbessern können:

$ { tail -f log_file & echo $! > pid; } | { grep -m1 "find_me" && kill -9 $(cat pid) && rm pid; }

Aufschlüsselung:

  1. tail -f log_file & echo $! > pid- legt eine Datei an, hängt den Prozess an den Hintergrund an und speichert die PID ( $!) in einer Datei. Ich habe versucht, die PID stattdessen in eine Variable zu exportieren, aber es scheint, als gäbe es eine Wettlaufsituation zwischen hier und dem Zeitpunkt, an dem die PID erneut verwendet wird.
  2. { ... ;}- Gruppieren Sie diese Befehle, damit wir die Ausgabe an grep leiten können, während der aktuelle Kontext beibehalten wird. (Hilft beim Speichern und Wiederverwenden von Variablen, konnte diesen Teil jedoch nicht zum Laufen bringen.)
  3. | - Leiten Sie den Abstand der linken Seite zum Abstand der rechten Seite
  4. grep -m1 "find_me" - Finden Sie die Zielzeichenfolge
  5. && kill -9 $(cat pid)- Erzwinge das Beenden (SIGKILL) des tailProzesses nach dem grep Beenden, sobald der passende String gefunden wurde
  6. && rm pid - Entfernen Sie die von uns erstellte Datei
Blake Regalia
quelle
0
my_cmd | tail +1f | sed '/String Im Looking For/q'

Wenn taildie +1fSyntax nicht unterstützt wird , versuchen Sie es tail -f -n +1. (Das -n +1weist es an, am Anfang zu beginnen. tail -fStandardmäßig beginnt es mit den letzten 10 Ausgabezeilen.)

Keith Thompson
quelle
Bitte beachten Sie mein Update auf die Frage.
gdw2
0

Hängen Sie das Ergebnis Ihrer Programmaufrufe an eine Datei an. Dann tail -fdiese Datei. So sollte es funktionieren ... hoffe ich.

Wenn Sie das Programm erneut aufrufen, müssen Sie die Datei löschen oder etwas Kauderwelsch anhängen, damit sie nicht gleich wieder mit dem übereinstimmt, wonach Sie gesucht haben.

Joanis
quelle