`tail -f` hasta que se vea el texto

20

Tengo un servidor CI con una interfaz de línea de comandos que me permite iniciar un trabajo de forma remota ( jenkinsservidor CI y la jenkins-cli.jarherramienta).

Después de iniciar el trabajo, tail -fel registro (perdón por el comando desordenado):

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

Después de que el trabajo se completa con éxito, generalmente después de al menos 5 minutos, obtengo la siguiente línea en la salida:

Finished: SUCCESS

¿Hay una buena manera de dejar de seguir el registro en este momento? es decir, hay como un tail_until 'some line' my-file.logcomando?

BONIFICACIÓN: crédito adicional si puede proporcionar una respuesta que devuelva 0 cuando el ÉXITO coincida, 1 cuando la FALLA coincida, ¡y su solución funciona en mac! (que creo que está basado en bsd)

aaronstacy
fuente

Respuestas:

39

Puede canalizar la tail -fentrada sedy decirle que se cierre cuando vea la línea que está buscando:

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

sedgenerará cada línea que procese de manera predeterminada y saldrá después de ver esa línea. El tailproceso se detendrá cuando intente escribir la siguiente línea y vea que su tubería de salida está rota

Michael Mrozek
fuente
booh si! Perfecto. ... por casualidad, ¿hay alguna forma de salir de 0 si coincido con una cosa (decir 'ÉXITO') y 1 si coincido con otra (como tal vez 'FALLO')?
aaronstacy
77
@aaronstacy Si está utilizando GNU grep, el qcomando toma un código de salida opcional. Entonces el sedcomando seríased '/^Finished: SUCCESS$/ q0; /^Finished: FAILURE$/ q1'
Michael Mrozek
66
Esto podría no funcionar si Finished: SUCCESSes la última línea de salida
lk-
@Michael Mrozek aaa y, por supuesto, no estoy b / c estoy usando friggin mac
aaronstacy
1
Esta solución tiene una falla importante: en mi caso, el registro termina en la línea buscada. No se escribirán más líneas para que el proceso permanezca estancado ya que la cola no tiene forma de romperse :(
Phate
6
tail -f my-file.log | grep -qx "Finished: SUCCESS"

-q, lo que significa tranquilo, se cierra tan pronto como encuentra una coincidencia

-xhace grepcoincidir toda la línea

Para la segunda parte, intente

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

-m <number>le dice a grep que pare después de que el número coincida

y el grep -qestado de salida solo será 0si SUCCESSse encuentra al final de la línea

Si desea ver toda la salida, no puede usar grep -q, pero aún puede hacer

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

que hace todo excepto establecer el estado de salida en 1 si FAILUREaparece.

Mikel
fuente
55
He utilizado grepen mi respuesta en un principio, pero si él está usando tail -fprobablemente quiere ver la salida del archivo; grepno va a mostrar todas las líneas intermedias
Michael Mrozek
4

Una variación en la respuesta de @ Mikel con los comentarios de @ Mrozek (habría respondido en el comentario pero creo que todavía no tengo suficientes privilegios)

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

le permitiría usar la solución de @ Mikel y aún ver el resultado en la pantalla

Chirlo
fuente
¿Podemos agregar un intervalo de tiempo de espera a esto, como: "si no se lee entre 60 y 120 segundos, entonces abortar la cola y dar un código de error de salida en el shell"?
kiltek
2

No me gustó ninguna de las respuestas aquí, así que decidí sacar la mía. Este script bash cumple con todos los criterios e incluye la BONIFICACIÓN para la salida de 1 en caso de falla.

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

También se incluye una función de tiempo de espera, que dará como resultado un código de salida de 3. Si no tiene el comando de tiempo de espera en su sistema, tome el script timeout.sh de Anthony Thyssen:

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

Según los comentarios a continuación, actualicé la impresión del registro para detener la expansión de caracteres de escape e incluí todas las características de una 'lectura' estándar. Consulte /programming//a/10929511 para obtener detalles completos de 'lectura'. Aquí no se requiere la verificación EOF, pero se incluye para completar.

verayth
fuente
Muy agradable. Considere usar while IFS= read -r LOGLINEpara evitar que el shell realice una división de espacios en blanco en las líneas tail.
roaima
@roaima: readno se divide cuando solo hay una variable (y no es una matriz con -a), pero es necesario -rsi los datos de entrada contienen una barra invertida. Pero si los datos de entrada contienen una barra invertida, entonces echo "$var"también pueden estropearse dependiendo de su shell y / o sistema, así que mejorprintf '%s\n' "$line"
dave_thompson_085
@ dave_thompson_085 Entendiendo "IFS = read -r line"
roaima
0

Aquí hay un script de Python que casi hace lo que quiero (ver las advertencias a continuación):

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

advertencias:

  • las líneas no se imprimen a medida que entran ... se imprimen en grupos ... parece que hay algo de almacenamiento en búfer

  • Tendría que instalar esto como una secuencia de comandos en mi ruta o algo así, por lo que es un inconveniente, y preferiría una línea pulida :)

aaronstacy
fuente
actualización: tailparece hacer el mismo almacenamiento en búfer, así que supongo que no es algo que valga la pena tratar de evitar.
aaronstacy
0

Tuve problemas con sedy grepsus opciones, así que escribo el míoone with bash conditions

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

También intentas

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