`tail -f` bis Text angezeigt wird

20

Ich habe einen CI-Server mit einer Befehlszeilenschnittstelle, mit der ich einen Auftrag remote starten kann ( jenkinsCI-Server und das jenkins-cli.jarTool).

Nachdem ich den Job gekickt habe habe ich tail -fdas Protokoll (sorry für den chaotischen Befehl):

ssh -t my-jenkins-host.com "tail -f \"/var/lib/jenkins/jobs/$job_name/builds/\`ls -ltr /var/lib/jenkins/jobs/$job_name/builds/ | grep '^l' | tail -n 1|awk '{print \$9}'\`/log\""

Nachdem der Auftrag erfolgreich abgeschlossen wurde, wird in der Regel nach mindestens 5 Minuten die folgende Zeile in der Ausgabe angezeigt:

Finished: SUCCESS

Gibt es eine gute Möglichkeit, das Protokoll an dieser Stelle nicht mehr zu verfolgen? dh gibt es wie ein tail_until 'some line' my-file.logbefehl?

BONUS: Zusätzliches Guthaben, wenn Sie eine Antwort liefern können, die 0 zurückgibt, wenn SUCCESS übereinstimmt, 1, wenn FAILURE übereinstimmt und Ihre Lösung auf einem Mac funktioniert! (Was ich glaube, ist BSD-basiert)

aaronstacy
quelle

Antworten:

39

Sie können die Eingabe mit der Pipe tail -fin sedbeenden, wenn die gesuchte Zeile angezeigt wird:

tail -f /path/to/file.log | sed '/^Finished: SUCCESS$/ q'

sedgibt jede Zeile aus, die standardmäßig verarbeitet wird, und beendet sich, nachdem diese Zeile angezeigt wird. Der tailProzess wird angehalten, wenn versucht wird, die nächste Zeile zu schreiben, und festgestellt wird, dass die Ausgabe-Pipe unterbrochen ist

Michael Mrozek
quelle
booh ja! perfekt. ... also gibt es zufällig eine Möglichkeit, 0 zu verlassen, wenn ich einer Sache entspreche (sagen Sie 'SUCCESS') und 1, wenn ich einer anderen Sache entspreche (wie vielleicht 'FAILURE')?
Aaronstacy
7
@aaronstacy Wenn Sie GNU grep verwenden, erhält der qBefehl einen optionalen Exit-Code. Das sedKommando wäre alsosed '/^Finished: SUCCESS$/ q0; /^Finished: FAILURE$/ q1'
Michael Mrozek
6
Dies funktioniert möglicherweise nicht, wenn Finished: SUCCESSes sich um die letzte Ausgabezeile handelt
lk-20.08.12
@ Michael Mrozek aaaand natürlich bin ich nicht b / c ich verwende verdammt mac
aaronstacy
1
Diese Lösung hat einen großen Fehler: In meinem Fall endet das Protokoll mit der gesuchten Zeile. Es werden keine weiteren Zeilen geschrieben, sodass der Prozess nicht beendet wird, da der Schwanz nicht brechen kann :(
Phate
6
tail -f my-file.log | grep -qx "Finished: SUCCESS"

-qwird beendet, sobald eine Übereinstimmung gefunden wird

-xmacht grepdie ganze Zeile passen

Versuchen Sie es im zweiten Teil

tail -f my-file.log | grep -m 1 "^Finished: " | grep -q "SUCCESS$"

-m <number>Weist grep an, anzuhalten, nachdem die Nummer übereinstimmt

und der grep -qExit-Status wird nur angezeigt, 0wenn SUCCESSam Ende der Zeile gefunden wird

Wenn Sie alle Ausgaben sehen möchten, können Sie sie nicht verwenden grep -q, aber Sie können es trotzdem tun

tail -f my-file.log | grep -m 1 "^Finished: "

Dadurch wird alles außer dem Ausgangsstatus auf 1 gesetzt, wenn FAILUREangezeigt wird.

Mikel
quelle
5
Ich grephabe es ursprünglich in meiner Antwort verwendet, aber wenn er es verwendet tail -f, möchte er wahrscheinlich die Dateiausgabe sehen. grepwird nicht alle Zwischenzeilen
Michael Mrozek
4

Eine Variation der Antwort von @ Mikel mit den Kommentaren von @ Mrozek (Ich hätte auf den Kommentar geantwortet, aber ich glaube, ich habe noch nicht genug Rechte)

tail -f my-file.log | tee >( grep -qx "Finished: SUCCESS" )

Damit können Sie die @ Mikel-Lösung verwenden und trotzdem die Ausgabe auf dem Bildschirm sehen

Chirlo
quelle
Können wir ein Timeout-Intervall hinzufügen, wie zum Beispiel: "Wenn es nicht zwischen 60 und 120 Sekunden gelesen wird, dann brechen Sie den Tail ab und geben Sie einen Fehler-Exit-Code in die Shell ein"?
15.
2

Ich mochte keine der Antworten hier, also beschloss ich, meine eigenen zu würfeln. Dieses Bash-Skript erfüllt alle Kriterien und enthält den BONUS für das Beenden von 1 bei einem Fehler.

#!/bin/bash
while IFS= read -r LOGLINE || [[ -n "$LOGLINE" ]]; do
    printf '%s\n' "$LOGLINE"
    [[ "${LOGLINE}" == "Finished: SUCCESS" ]] && exit 0
    [[ "${LOGLINE}" == "Finished: FAILURE" ]] && exit 1
done < <(timeout 300 tail -f my-file.log)
exit 3

Ebenfalls enthalten ist eine Timeout-Funktion, die einen Exit-Code von 3 ergibt. Wenn Sie den Timeout-Befehl nicht auf Ihrem System haben, rufen Sie das Skript timeout.sh von Anthony Thyssen auf:

http://www.ict.griffith.edu.au/anthony/software/timeout.sh

Gemäß den Kommentaren unten habe ich den Protokolldruck aktualisiert, um die Escape-Zeichenerweiterung zu stoppen, und alle Funktionen eines Standard-Lesevorgangs aufgenommen. Ausführliche Informationen zum Lesen finden Sie unter /programming//a/10929511 . Die EOF-Prüfung ist hier nicht erforderlich, aber der Vollständigkeit halber enthalten.

Verayth
quelle
Sehr schön. Erwägen Sie die Verwendung von while IFS= read -r LOGLINE, um zu verhindern, dass die Shell Leerzeichen in den Zeilen von aufteilt tail.
Roaima
@roaima: Wird readnicht geteilt, wenn es nur eine Variable gibt (und es ist kein Array mit -a), aber Sie müssen, -rwenn die Eingabedaten einen Backslash enthalten. Wenn die Eingabedaten jedoch einen Backslash enthalten, echo "$var"kann dies je nach Shell und / oder System auch zu printf '%s\n' "$line"
Problemen führen. Also
@ Dave_Thompson_085 Understanding "IFS = read -r Zeile"
Roaima
0

Hier ist ein Python-Skript, das beinahe das macht, was ich will (siehe unten):

import sys,re

def main():
    re_end = re.compile(sys.argv[1])
    re_fail = re.compile(sys.argv[2]) if len(sys.argv) > 2 else None
    for line in sys.stdin:
        sys.stdout.write(line)
        if re_end.match(line):
            sys.exit(0)
        elif re_fail and re_fail.match(line):
            sys.exit(1)

if __name__ == '__main__': main()

Vorbehalte:

  • Die Zeilen werden nicht gedruckt, wenn sie eingehen. Sie werden in Gruppen gedruckt

  • Ich müsste dies als Skript auf meinem Pfad oder so etwas installieren, so ist es unpraktisch, und ich würde einen glatten Einzeiler bevorzugen :)

aaronstacy
quelle
update: tailscheint dasselbe zu tun, also ist es wohl nicht wert, es zu versuchen, es zu umgehen.
Aaronstacy
0

Ich hatte Probleme mit sedund grepund ihren Optionen, also schreibe ich meineone with bash conditions

tail -f screenlog.* | 
while IFS= read line; 
 do 
   echo $line; 
   if [[ $line == *Started\ Application* ]]; 
    then pkill tail; 
   fi; 
done
Panser
quelle
-1

Du versuchst es auch

 grep -q 'App Started' <(tail -f /var/log/app/app.log)
Deano
quelle