`tail -f` jusqu'à ce que le texte soit vu

20

J'ai un serveur CI avec une interface de ligne de commande qui me permet de lancer un travail à distance ( jenkinsserveur CI et l' jenkins-cli.jaroutil).

Après avoir lancé le travail, je tail -fle journal (désolé pour la commande en désordre):

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

Une fois le travail terminé, généralement après au moins 5 minutes, j'obtiens la ligne suivante sur la sortie:

Finished: SUCCESS

Existe-t-il un bon moyen d'arrêter de suivre le journal à ce stade? c'est à dire qu'il y a comme une tail_until 'some line' my-file.logcommande?

BONUS: crédit supplémentaire si vous pouvez fournir une réponse qui renvoie 0 lorsque SUCCESS est apparié, 1 lorsque FAILURE est apparié et que votre solution fonctionne sur mac! (qui je crois est basé sur bsd)

aaronstacy
la source

Réponses:

39

Vous pouvez diriger le tail -fdans sed, lui disant de quitter quand il voit la ligne que vous recherchez:

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

sedaffichera chaque ligne qu'il traite par défaut et quittera après avoir vu cette ligne. Le tailprocessus s'arrête lorsqu'il essaie d'écrire la ligne suivante et voit que son canal de sortie est cassé

Michael Mrozek
la source
booh oui! parfait. ... donc, par hasard, existe-t-il un moyen de quitter 0 si je fais correspondre une chose (dites «SUCCÈS») et 1 si je fais correspondre autre chose (comme peut-être «ÉCHEC»)?
aaronstacy
7
@aaronstacy Si vous utilisez GNU grep, la qcommande prend un code de sortie facultatif. Donc la sedcommande seraitsed '/^Finished: SUCCESS$/ q0; /^Finished: FAILURE$/ q1'
Michael Mrozek
6
Cela pourrait ne pas fonctionner si Finished: SUCCESSc'est la dernière ligne de sortie
lk-
@Michael Mrozek aaaet bien sûr je ne suis pas b / c
j'utilise friggin
1
Cette solution a un défaut majeur: dans mon cas, le journal se termine par la ligne recherchée. Plus aucune ligne ne sera écrite afin que le processus reste bloqué car la queue n'a aucun moyen de casser :(
Phate
6
tail -f my-file.log | grep -qx "Finished: SUCCESS"

-q, ce qui signifie calme, quitte dès qu'il trouve une correspondance

-xfait grepcorrespondre la ligne entière

Pour la deuxième partie, essayez

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

-m <number>demande à grep de s'arrêter après la correspondance des numéros

et l' grep -qétat de sortie ne sera que 0s'il SUCCESSest trouvé à la fin de la ligne

Si vous voulez voir toute la sortie, vous ne pouvez pas l'utiliser grep -q, mais vous pouvez toujours le faire

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

qui fait tout sauf mettre l'état de sortie à 1 si FAILUREapparaît.

Mikel
la source
5
J'ai utilisé grepdans ma réponse à l'origine, mais s'il utilise, tail -fil veut probablement voir la sortie du fichier; grepne va pas montrer toutes les lignes intermédiaires
Michael Mrozek
4

Une variation sur la réponse de @ Mikel avec les commentaires de @ Mrozek (j'aurais répondu sur le commentaire mais je pense que je n'ai pas encore assez de privilèges)

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

vous permettrait d'utiliser la solution de @ Mikel et de voir la sortie à l'écran

Chirlo
la source
Pouvons-nous ajouter un intervalle de temporisation à ceci, comme: "s'il n'est pas lu entre 60 et 120 secondes, alors abandonner la queue et donner un code de sortie d'erreur dans le shell"?
kiltek
2

Je n'ai aimé aucune des réponses ici, alors j'ai décidé de lancer la mienne. Ce script bash répond à tous les critères et inclut le BONUS pour la sortie de 1 en cas d'échec.

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

Une fonction timeout est également incluse, ce qui entraînera un code de sortie de 3. Si vous n'avez pas la commande timeout sur votre système, récupérez le script timeout.sh d'Anthony Thyssen:

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

D'après les commentaires ci-dessous, j'ai mis à jour l'impression du journal pour arrêter l'expansion des caractères d'échappement et inclus toutes les fonctionnalités d'une lecture standard. Voir /programming//a/10929511 pour les détails complets de «lecture». Le contrôle EOF n'est pas requis ici, mais est inclus pour être complet.

verayth
la source
Très agréable. Pensez à utiliser while IFS= read -r LOGLINEpour empêcher le shell d'effectuer un fractionnement des espaces sur les lignes tail.
roaima
@roaima: readne se divise pas lorsqu'il n'y a qu'une seule variable (et ce n'est pas un tableau avec -a), mais vous en avez besoin -rsi les données d'entrée contiennent une barre oblique inverse. Mais si les données d'entrée contiennent une barre oblique inverse, elles echo "$var"peuvent également bousiller en fonction de votre shell et / ou de votre système, donc mieuxprintf '%s\n' "$line"
dave_thompson_085
@ dave_thompson_085 Comprendre "IFS = read -r line"
roaima
0

voici un script python qui fait presque ce que je veux (voir les mises en garde ci-dessous):

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

mises en garde:

  • les lignes ne sont pas imprimées à mesure qu'elles entrent ... elles sont imprimées en groupes ... semble être un tampon en cours

  • je devrais l'installer en tant que script sur mon chemin ou quelque chose, donc ce n'est pas pratique, et je préférerais une ligne lisse :)

aaronstacy
la source
mise à jour: tailsemble faire la même mise en mémoire tampon, donc je suppose que ce n'est pas quelque chose qui mérite d'être essayé.
aaronstacy
0

J'ai eu des problèmes avec sedet grepet leurs options, alors j'écris les miennesone with bash conditions

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

Vous essayez aussi

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