`tail -f`, aż pojawi się tekst

20

Mam serwer CI z interfejsem wiersza polecenia, który pozwala mi na zdalne rozpoczęcie zadania ( jenkinsserwer CI i jenkins-cli.jarnarzędzie).

Po wykopaniu zadania I tail -flog (przepraszam za niechlujne polecenie):

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\""

Po pomyślnym zakończeniu zadania, zwykle po co najmniej 5 minutach, na wyjściu pojawia się następujący wiersz:

Finished: SUCCESS

Czy istnieje dobry sposób, aby w tym momencie przestać śledzić dziennik? tzn. czy jest jak tail_until 'some line' my-file.logpolecenie?

BONUS: dodatkowy kredyt, jeśli możesz podać odpowiedź, która zwraca 0, gdy SUKCES jest dopasowany, 1, gdy BŁĄD jest dopasowany, a twoje rozwiązanie działa na Macu! (który moim zdaniem jest oparty na bsd)

aaronstacy
źródło

Odpowiedzi:

39

Możesz przesłać potok tail -fdo sed, mówiąc mu, aby zakończył pracę, gdy zobaczy linię, której szukasz:

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

sedwyświetli każdą linię, którą przetwarza domyślnie, i zakończy działanie po zobaczeniu tej linii. tailProces zatrzyma się, gdy próbuje napisać następną linię i widzi jego rura wyjściowa jest uszkodzony

Michał Mrożek
źródło
boo tak! doskonały. ... więc czy istnieje szansa na wyjście 0 jeśli pasuję do jednej rzeczy (powiedz „SUKCES”) i 1, jeśli pasuję do czegoś innego (np. „AWARIA”)?
aaronstacy,
7
@aaronstacy Jeśli używasz GNU grep, qpolecenie pobiera opcjonalny kod wyjścia. Tak więc sedkomenda brzmiałabysed '/^Finished: SUCCESS$/ q0; /^Finished: FAILURE$/ q1'
Michał Mrożek
6
Może to nie działać, jeśli Finished: SUCCESSjest to ostatni wiersz wyniku
lk-
@Michael Mrozek aaa i oczywiście nie jestem b / c używam friggin mac
aaronstacy
1
To rozwiązanie ma poważną wadę: w moim przypadku dziennik kończy się na przeszukiwanej linii. Nie będą już zapisywane żadne wiersze, więc proces utknie, ponieważ ogon nie ma możliwości złamania :(
Phate
6
tail -f my-file.log | grep -qx "Finished: SUCCESS"

-q, co oznacza cicho, kończy się, gdy tylko znajdzie dopasowanie

-xmarki grepdopasować cały wiersz

W drugiej części spróbuj

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

-m <number>każe grepowi zatrzymać się po dopasowaniu numeru

a grep -qstatus wyjścia będzie tylko 0wtedy, gdy SUCCESSzostanie znaleziony na końcu linii

Jeśli chcesz zobaczyć wszystkie dane wyjściowe, nie możesz użyć grep -q, ale nadal możesz to zrobić

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

który robi wszystko oprócz ustawienia statusu wyjścia na 1, jeśli się FAILUREpojawi.

Mikel
źródło
5
Użyłem greppierwotnie w mojej odpowiedzi, ale jeśli używa tail -f, prawdopodobnie chce zobaczyć plik wyjściowy; grepnie pokaże wszystkich linii pośrednich
Michael Mrozek
4

Odmiana odpowiedzi @ Mikela z komentarzami @ Mrożka (odpowiedziałbym na komentarz, ale myślę, że nie mam jeszcze wystarczających uprawnień)

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

pozwoli ci skorzystać z rozwiązania @ Mikela i nadal wyświetla dane wyjściowe na ekranie

Chirlo
źródło
Czy możemy dodać do tego przedział limitu czasu, na przykład: „jeśli nie zostanie odczytany od 60 do 120 sekund, to przerwij ogon i podaj kod wyjścia błędu w powłoce”?
kiltek
2

Nie podoba mi się żadna z odpowiedzi tutaj, więc postanowiłem rzucić własną. Ten skrypt bash spełnia wszystkie kryteria i zawiera BONUS za wyjście 1 w przypadku awarii.

#!/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

Uwzględniono również funkcję limitu czasu, która spowoduje kod wyjścia 3. Jeśli nie masz w swoim systemie polecenia limitu czasu, pobierz skrypt timeout.sh z Anthony'ego Thyssena:

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

Zgodnie z poniższymi komentarzami zaktualizowałem wydruk dziennika, aby zatrzymać ekspansję znaków ucieczki i zawarłem wszystkie funkcje standardowego „odczytu”. Zobacz /programming//a/10929511, aby uzyskać pełne szczegóły „czytaj”. Kontrola EOF nie jest tutaj wymagana, ale jest uwzględniona dla kompletności.

Verayth
źródło
Bardzo dobrze. Rozważ użycie, while IFS= read -r LOGLINEaby uniemożliwić powłoce wykonywanie podziału białych znaków na liniach od tail.
roaima,
@roaima: readnie dzieli się, gdy istnieje tylko jedna zmienna (i nie jest to tablica z -a), ale potrzebujesz, -rjeśli dane wejściowe zawierają ukośnik odwrotny. Ale jeśli dane wejściowe zawierają ukośnik odwrotny, to echo "$var"może również printf '%s\n' "$line"
popsuć
@ dave_thompson_085 Zrozumienie „IFS = read -r line”
roaima
0

Oto skrypt Pythona, który prawie robi to, co chcę (patrz zastrzeżenia poniżej):

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()

zastrzeżenia:

  • wiersze nie są drukowane po ich wejściu ... są drukowane w grupach ... wydaje się, że trwa buforowanie

  • musiałbym zainstalować to jako skrypt na mojej ścieżce lub coś w tym stylu, więc jest to niewygodne i wolałbym zręczny jednoliniowy :)

aaronstacy
źródło
aktualizacja: tailwydaje się, że robi to samo buforowanie, więc zgaduję, że nie warto tego próbować obejść.
aaronstacy,
0

Miałem problemy z sedi grepi ich możliwości, więc piszę kopalnione with bash conditions

tail -f screenlog.* | 
while IFS= read line; 
 do 
   echo $line; 
   if [[ $line == *Started\ Application* ]]; 
    then pkill tail; 
   fi; 
done
panser
źródło
-1

Ty też próbujesz

 grep -q 'App Started' <(tail -f /var/log/app/app.log)
Deano
źródło