`tail -f` fino a quando non viene visualizzato il testo


20

Ho un server CI con un'interfaccia a riga di comando che mi consente di avviare da remoto un lavoro ( jenkinsserver CI e lo jenkins-cli.jarstrumento).

Dopo aver dato il via al lavoro ho tail -fil registro (scusate il comando disordinato):

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

Al termine del processo, in genere dopo almeno 5 minuti, sull'output viene visualizzata la seguente riga:

Finished: SUCCESS

Esiste un buon modo per smettere di seguire il registro a questo punto? cioè c'è un tail_until 'some line' my-file.logcomando?

BONUS: credito extra se puoi fornire una risposta che restituisce 0 quando SUCCESS è abbinato, 1 quando FAILURE è abbinato e la tua soluzione funziona su Mac! (che credo sia basato su bsd)

Risposte:


39

Puoi reindirizzare tail -fin sed, dicendo di uscire quando vede la linea che stai cercando:

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

sedprodurrà ogni linea che elabora per impostazione predefinita e uscirà dopo aver visto quella linea. Il tailprocesso si interromperà quando proverà a scrivere la riga successiva e vedrà che la sua pipe di output è rotta


ciao sì! Perfetto. ... quindi per caso c'è un modo per uscire da 0 se abbino una cosa (dire 'SUCCESSO') e 1 se abbino qualcos'altro (come forse 'FAILURE')?
aaronstacy

7
@aaronstacy Se stai usando GNU grep, il qcomando accetta un codice di uscita opzionale. Quindi il sedcomando sarebbesed '/^Finished: SUCCESS$/ q0; /^Finished: FAILURE$/ q1'
Michael Mrozek

6
Questo potrebbe non funzionare se Finished: SUCCESSè l'ultima riga di output
lk-

@Michael Mrozek aaaand ovviamente non sono b / c sto usando friggin mac
aaronstacy

1
Questa soluzione ha un grosso difetto: nel mio caso il registro termina con la riga cercata. Non verranno più scritte righe in modo che il processo rimanga bloccato poiché la coda non ha modo di spezzarsi :(
Phate

6
tail -f my-file.log | grep -qx "Finished: SUCCESS"

-q, che significa silenzioso, si chiude non appena trova una corrispondenza

-xfa grepcorrispondere l'intera linea

Per la seconda parte, prova

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

-m <number>dice a grep di fermarsi dopo le corrispondenze numeriche

e lo grep -qstato di uscita sarà solo 0se SUCCESSsi trova alla fine della riga

Se vuoi vedere tutto l'output, non puoi usarlo grep -q, ma puoi ancora farlo

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

che fa tutto tranne impostare lo stato di uscita su 1 se FAILUREappare.


5
grepInizialmente ho usato la mia risposta, ma se lo sta usando tail -fprobabilmente vuole vedere l'output del file; grepnon mostrerà tutte le linee intermedie
Michael Mrozek

4

Una variazione sulla risposta di @ Mikel con i commenti di @ Mrozek (avrei risposto al commento ma penso di non avere ancora abbastanza privilegi)

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

ti permetterebbe di utilizzare la soluzione di @ Mikel e di vedere comunque l'output sullo schermo


Possiamo aggiungere un intervallo di timeout a questo, come: "se non viene letto tra 60 e 120 secondi, quindi interrompere la coda e dare un codice di uscita di errore nella shell"?
Kiltek,

2

Non mi è piaciuta nessuna delle risposte qui, quindi ho deciso di dare il mio. Questo script bash soddisfa tutti i criteri e include il BONUS per l'uscita di 1 in caso di errore.

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

È inclusa anche una funzione di timeout, che comporterà un codice di uscita di 3. Se non si dispone del comando timeout sul proprio sistema, prendere lo script timeout.sh da Anthony Thyssen:

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

In base ai commenti seguenti, ho aggiornato la stampa del registro per interrompere l'espansione del carattere di escape e ho incluso tutte le funzionalità di una "lettura" standard. Vedere /programming//a/10929511 per i dettagli completi di "lettura". Il controllo EOF non è richiesto qui, ma è incluso per completezza.


Molto bella. Considerare l'utilizzo while IFS= read -r LOGLINEper evitare che la shell esegua la divisione degli spazi bianchi sulle linee tail.
roaima,

@roaima: readnon si divide quando c'è solo una variabile (e non è un array con -a), ma è necessario -rse i dati di input contengono una barra rovesciata. Ma se i dati di input contengono una barra rovesciata, echo "$var"potrebbero anche rovinarsi a seconda della shell e / o del sistema, quindi meglioprintf '%s\n' "$line"
dave_thompson_085


0

ecco uno script Python che fa quasi quello che voglio (vedi avvertenze di seguito):

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

avvertimenti:

  • le linee non vengono stampate man mano che entrano ... sono stampate in gruppi ... sembra essere in corso un buffering

  • dovrei installarlo come uno script sul mio percorso o qualcosa del genere, quindi è scomodo, e preferirei uno slick one-liner :)


aggiornamento: tailsembra fare lo stesso buffering, quindi immagino che non valga la pena provare a aggirare.
aaronstacy

0

Ho avuto problemi con sede grepe le loro opzioni, in modo che scrivo la miaone with bash conditions

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

-1

Ci provi anche tu

 grep -q 'App Started' <(tail -f /var/log/app/app.log)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.