J'utilise tail -f pour surveiller un fichier journal en cours d'écriture. Lorsqu'une certaine chaîne est écrite dans le fichier journal, je souhaite quitter la surveillance et poursuivre le reste de mon script.
Actuellement, j'utilise:
tail -f logfile.log | grep -m 1 "Server Started"
Lorsque la chaîne est trouvée, grep se ferme comme prévu, mais je dois trouver un moyen de faire quitter également la commande tail afin que le script puisse continuer.
tail
matrices ne s'affichent qu'à la ligne suivante. Essayez ceci:date > log; tail -f log | grep -m 1 trigger
et ensuite dans un autre shell:echo trigger >> log
et vous verrez le résultattrigger
dans le premier shell, mais pas de fin de la commande. Ensuite, essayez:date >> log
dans le deuxième shell et la commande dans le premier shell se terminera. Mais parfois c'est trop tard; nous voulons terminer dès que la ligne de déclenchement est apparue, pas lorsque la ligne après la ligne de déclenchement est terminée.tail
+grep -q
comme la réponse de 00prometheusRéponses:
Une simple doublure POSIX
Voici un simple one-liner. Il n'a pas besoin d'astuces spécifiques à bash ou non-POSIX, ni même de pipe nommée. Tout ce que vous avez vraiment besoin est de découpler la fin de
tail
partirgrep
. Ainsi, une foisgrep
terminé, le script peut continuer même s'iltail
n'est pas encore terminé. Donc, cette méthode simple vous y mènera:grep
bloque jusqu’à ce qu’il ait trouvé la chaîne, puis quitte. En exécutanttail
à partir de son propre sous-shell, nous pouvons le placer en arrière-plan afin qu'il s'exécute indépendamment. Pendant ce temps, le shell principal est libre de continuer à exécuter le script dès sagrep
sortie.tail
s'attardera dans son sous-shell jusqu'à ce que la ligne suivante soit écrite dans le fichier journal, puis se terminera (éventuellement même après la fin du script principal). Le point principal est que le pipeline n'attend plus latail
fin, de sorte qu'il se ferme dès lagrep
sortie.Quelques modifications mineures:
tail
permet de commencer à lire à partir de la dernière ligne actuelle du fichier journal, au cas où la chaîne existe plus tôt dans le fichier journal.tail
-F plutôt que -f. Ce n'est pas POSIX, mais cela permettail
de travailler même si le journal est pivoté pendant l'attente.grep
quitter après la première occurrence, mais sans afficher la ligne de déclenchement. En outre, c'est POSIX, ce que -m1 ne l'est pas.la source
tail
course en arrière-plan pour toujours. Comment voulez-vous capturer letail
PID dans le sous-shell en arrière-plan et l'exposer au shell principal? Je ne peux que trouver la solution de contournement sous-optionnelle en supprimant tous lestail
processus de session attachés , en utilisantpkill -s 0 tail
.tail
se terminera dès qu’il essaiera d’écrire sur un tuyau cassé. Le tuyau se cassera dès qu'ilgrep
sera terminé, donc une foisgrep
terminé, iltail
se terminera une fois que le fichier journal aura reçu une ligne supplémentaire.tail -f
.La réponse acceptée ne fonctionne pas pour moi. En plus, c'est déroutant et cela change le fichier journal.
J'utilise quelque chose comme ça:
Si la ligne de journal correspond au modèle, supprimez le
tail
démarré par ce script.Remarque: si vous souhaitez également afficher le résultat à l’écran, vous pouvez soit afficher
| tee /dev/tty
la ligne avant de tester la boucle while.la source
pkill
n'est pas spécifié par POSIX et n'est pas disponible partout.Si vous utilisez Bash (du moins, mais il semble que ce ne soit pas défini par POSIX, il est peut-être manquant dans certains shells), vous pouvez utiliser la syntaxe
Cela fonctionne assez bien comme les solutions FIFO déjà mentionnées, mais beaucoup plus simple à écrire.
la source
SIGTERM
(Ctrl + C, une commande de sortie ou le tue-le)tail
lira, essaiera de le sortir puis recevra un SIGPIPE qui le terminera. Donc, en principe, vous avez raison. letail
peut fonctionner indéfiniment si rien n'est jamais écrit dans le fichier journal. En pratique, cela pourrait être une solution très intéressante pour beaucoup de gens.Il y a plusieurs façons
tail
de sortir:Mauvaise approche: forcer
tail
à écrire une autre ligneVous pouvez forcer l'
tail
écriture d'une autre ligne de sortie immédiatement aprèsgrep
avoir trouvé une correspondance et quitté. Cela entraîneratail
unSIGPIPE
, le faisant sortir. Une façon de faire est de modifier le fichier en cours de surveillancetail
après lesgrep
sorties.Voici un exemple de code:
Dans cet exemple,
cat
ne quittera pas tant qu'il n'aura pasgrep
fermé sa stdout. Par conséquent, iltail
est peu probable qu'il puisse écrire sur le canal avant d'grep
avoir eu la chance de fermer son stdin.cat
est utilisé pour propager la sortie standard degrep
non modifié.Cette approche est relativement simple, mais il y a plusieurs inconvénients:
grep
ferme stdout avant stdin, il y aura toujours une condition degrep
concurrence : ferme stdout, déclenche lacat
sortie, déclencheecho
, déclenche latail
sortie d'une ligne. Si cette ligne est envoyée àgrep
avant, ellegrep
a eu la chance de fermer stdin,tail
elle ne l’aura pasSIGPIPE
jusqu’à ce qu’elle écrive une autre ligne.tail
- cela ne fonctionnera pas avec d'autres programmes.bash
'PIPESTATUS
array'). Ce n’est pas un gros problème dans ce cas, cargrep
il retournera toujours 0, mais en général, l’étage intermédiaire peut être remplacé par une commande différente dont vous vous souciez du code de retour (par exemple, quelque chose qui retourne 0 quand "serveur démarré" est détecté, 1 lorsque "échec du démarrage du serveur" est détecté).Les approches suivantes évitent ces limitations.
Une meilleure approche: éviter les pipelines
Vous pouvez utiliser une FIFO pour éviter complètement le pipeline, permettant ainsi à l'exécution de continuer une fois
grep
renvoyé. Par exemple:Les lignes marquées avec le commentaire
# optional
peuvent être supprimées et le programme fonctionnera toujours;tail
s'attardera jusqu'à ce qu'il lit une autre ligne d'entrée ou soit tué par un autre processus.Les avantages de cette approche sont les suivants:
tail
grep
(ou toute autre commande que vous utilisez)L'inconvénient de cette approche est la complexité, en particulier la gestion de la FIFO: vous devez générer de manière sécurisée un nom de fichier temporaire et vous assurer que la FIFO temporaire est supprimée même si l'utilisateur appuie sur Ctrl-C au milieu de le scénario. Cela peut être fait en utilisant un piège.
Approche alternative: Envoyer un message à Kill
tail
Vous pouvez obtenir la fin de
tail
la phase de pipeline en lui envoyant un signal du typeSIGTERM
. Le défi consiste à connaître de manière fiable deux choses au même endroit dans le code:tail
le PID de et sigrep
s'est terminé.Avec un pipeline de type
tail -f ... | grep ...
, il est facile de modifier le premier étage de pipeline pour enregistrertail
le PID dans une variable en arrièretail
- plan et en lecture$!
. Il est également facile de modifier le deuxième étage de pipeline pour qu'il s'exécutekill
lors de lagrep
sortie. Le problème est que les deux étapes du pipeline s'exécutent dans des "environnements d'exécution" distincts (dans la terminologie de la norme POSIX), de sorte que la deuxième étape de pipeline ne peut lire aucune variable définie par l'étape de pipeline précédente. Sans l' aide de variables shell, soit la deuxième étape doit comprendre en quelque sorte horstail
PID » afin qu'il puisse tuertail
quand lesgrep
retours, ou la première étape doit en quelque sorte être averti lorsque legrep
rendement.La deuxième étape pourrait utiliser
pgrep
pour obtenirtail
le PID, mais ce serait peu fiable (vous pourriez correspondre au mauvais processus) et non portable (cepgrep
n’est pas spécifié par la norme POSIX).La première étape pourrait envoyer le PID à la deuxième étape via le tuyau en utilisant
echo
le PID, mais cette chaîne sera mélangée àtail
la sortie de. Le démultiplexage des deux peut nécessiter un schéma d'échappement complexe, en fonction du résultat detail
.Vous pouvez utiliser une FIFO pour que le deuxième étage de pipeline informe le premier étage de pipeline lors de sa
grep
sortie. Alors la première étape peut tuertail
. Voici un exemple de code:Cette approche présente tous les avantages et les inconvénients de l'approche précédente, à l'exception que ce soit plus compliqué.
Un avertissement sur la mise en mémoire tampon
POSIX permet aux flux stdin et stdout d'être entièrement mis en mémoire tampon, ce qui signifie que
tail
la sortie risque de ne pas être traitéegrep
pendant un temps arbitrairement long. Il ne devrait y avoir aucun problème sur les systèmes GNU: GNUgrep
utiliseread()
, ce qui évite toute mise en mémoire tampon, et GNUtail -f
appelle régulièrement à l'fflush()
écriture sur stdout. Les systèmes non-GNU peuvent avoir à faire quelque chose de spécial pour désactiver ou vider régulièrement les tampons.la source
tail -f
ne sortira que les dix dernières lignes, puis toutes les suivantes. Pour améliorer cela, vous pouvez ajouter l'option-n 10000
à la queue afin que les 10000 dernières lignes soient également affichées.tail -f
par la fifo et grep dessus:mkfifo f; tail -f log > f & tailpid=$! ; grep -m 1 trigger f; kill $tailpid; rm f
.tail -f log
écriture dans une FIFO fera en sorte que certains systèmes (par exemple, GNU / Linux) utilisent la mise en mémoire tampon basée sur des blocs au lieu de la mise en mémoire tampon basée sur les lignes, ce qui signifiegrep
que la ligne correspondante apparaît dans le journal. Le système peut fournir un utilitaire pour changer la mise en mémoire tampon, par exemple àstdbuf
partir de GNU coreutils. Un tel utilitaire serait toutefois non portable.grep -q -m 1 trigger <(tail -f log)
proposée ailleurs et je vis avec le fait que latail
ligne passe une ligne plus longue en arrière-plan que nécessaire.Permettez-moi de développer la réponse @ 00prometheus (qui est la meilleure).
Peut-être devriez-vous utiliser un délai d'attente au lieu d'attendre indéfiniment.
La fonction bash ci-dessous bloquera jusqu'à ce que le terme de recherche donné apparaisse ou qu'un délai d'expiration donné soit atteint.
L'état de sortie sera 0 si la chaîne est trouvée dans le délai imparti.
Peut-être que le fichier journal n'existe pas encore juste après le lancement de votre serveur. Dans ce cas, vous devez attendre son apparition avant de rechercher la chaîne:
Voici comment vous pouvez l'utiliser:
la source
timeout
commande?timeout
est le seul moyen fiable de ne pas suspendre indéfiniment l'attente d'un serveur qui ne peut pas démarrer et qui est déjà sorti.Donc, après avoir fait quelques essais, j'ai trouvé un moyen rapide, en une ligne, de faire en sorte que cela fonctionne. Il semble que tail -f se ferme quand grep se ferme, mais il y a un piège. Il semble ne se déclencher que si le fichier est ouvert et fermé. Pour ce faire, j'ai ajouté la chaîne vide au fichier lorsque grep a trouvé la correspondance.
Je ne suis pas sûr de savoir pourquoi l'ouverture / la fermeture du fichier amène la queue à se rendre compte que le tuyau est fermé, aussi je ne compterais pas sur ce comportement. mais cela semble fonctionner pour le moment.
Raison pour laquelle il ferme, regardez le drapeau -F, par rapport au drapeau -f.
la source
tail
sortie d'une autre ligne, mais qu'ilgrep
est maintenant terminé (probablement - il y a une condition de concurrence critique). Sigrep
a fini par le tempstail
écrit une autre ligne,tail
obtiendra unSIGPIPE
. Cela provoque latail
sortie tout de suite.tail
(6) vous ne pouvez pas facilement le modifier différemment en fonction des correspondances de chaînes ("serveur démarré" ou "serveur échoué") car vous ne pouvez pas obtenir facilement le code retour du stade intermédiaire du pipeline. Il existe une approche alternative qui évite tous ces problèmes - voir ma réponse.Actuellement, comme indiqué, toutes les
tail -f
solutions ici risquent de capturer une ligne "Serveur démarré" précédemment enregistrée (ce qui peut être un problème dans votre cas spécifique, en fonction du nombre de lignes enregistrées et de la rotation du fichier journal / troncature).Plutôt que de trop compliquer les choses, utilisez simplement une méthode plus intelligente
tail
, comme le montre bmike avec un extrait de Perl. La solution la plus simple est celleretail
qui intègre le support regex avec des modèles de conditions de démarrage et d' arrêt :Cela suivra le fichier comme une normale
tail -f
jusqu'à ce que la première nouvelle instance de cette chaîne apparaisse, puis se fermera. (L'-u
option ne se déclenche pas sur les lignes existantes des 10 dernières lignes du fichier en mode "normal".)Si vous utilisez GNU
tail
(de coreutils ), l’option la plus simple suivante consiste à utiliser--pid
une FIFO (nommée pipe):Une FIFO est utilisée car les processus doivent être démarrés séparément pour obtenir et transmettre un PID. Une FIFO souffre toujours du même problème d’attente pour une écriture opportune afin
tail
de recevoir un SIGPIPE , utilisez l’--pid
option de manière à ce que lestail
sorties se fassent à lagrep
fin de la session (classiquement utilisée pour surveiller le processus d’ écriture plutôt que le lecteur , maistail
ne le fait pas. t s'en soucie vraiment). L'option-n 0
est utilisée avectail
pour que les anciennes lignes ne déclenchent pas de correspondance.Enfin, vous pouvez utiliser une queue avec état , ceci stockera le décalage de fichier actuel afin que les appels suivants ne montrent que les nouvelles lignes (il gère également la rotation de fichier). Cet exemple utilise l'ancien FWTK
retail
*:* Remarque, même nom, programme différent de l'option précédente.
Plutôt que d'avoir une boucle monopolisation de la CPU, comparez l'horodatage du fichier avec le fichier d'état (
.${LOGFILE}.off
), et mettez en veille. Utilisez "-T
" pour spécifier l'emplacement du fichier d'état, le cas échéant, le répertoire ci-dessus est supposé. N'hésitez pas à ignorer cette condition, ou sous Linux, vous pouvez utiliser le plus efficace à lainotifywait
place:la source
retail
avec un dépassement de délai, par exemple: "Si 120 secondes se sont écoulées et que le point de vente n'a toujours pas lu la ligne, donnez un code d'erreur et quittez le point de vente au détail"?timeout
(coreutils) pour se lancerretail
et vérifie simplement que le code de sortie 124 est expiré (latimeout
commande que vous utiliserez seraCe sera un peu délicat, car vous devrez entrer dans le contrôle et la signalisation du processus. Plus kludgey serait une solution à deux scripts utilisant le suivi PID. Mieux vaut utiliser des tubes nommés comme celui-ci.
Quel script shell utilisez-vous?
Pour une solution de script rapide et sale, je créerais un script Perl en utilisant File: Tail
Ainsi, plutôt que d'imprimer à l'intérieur de la boucle while, vous pouvez filtrer la correspondance de chaîne et sortir de la boucle while pour laisser votre script se poursuivre.
L'une ou l'autre de ces opérations devrait impliquer un peu d'apprentissage pour mettre en œuvre le contrôle de flux d'observation que vous recherchez.
la source
maxinterval=>300
signifie qu'il vérifiera le fichier toutes les cinq minutes. Comme je sais que ma ligne apparaîtra dans le fichier dans un moment, j'utilise des sondages beaucoup plus agressifs:maxinterval=>0.2, adjustafter=>10000
attendre que le fichier apparaisse
attendre que la chaîne apparaisse dans le fichier
https://superuser.com/a/743693/129669
la source
/path/to/the.file
qui est de 1,4 Go de large; alors il est clair que c'est un problème. 2. Il attend plus longtemps que nécessaire lorsque l'entrée du journal est apparue, dans le pire des cas 10s.Je ne peux pas imaginer une solution plus propre que celle-ci:
ok, peut-être que le nom peut être sujet à des améliorations ...
Avantages:
la source
Vous n'avez pas nécessairement besoin de queue pour le faire. Je pense que la commande de surveillance est ce que vous recherchez. La commande watch surveille la sortie d'un fichier et peut être terminée avec l' option -g lorsque la sortie est modifiée.
la source
Alex, je pense que celui-ci vous aidera beaucoup.
cette commande ne donnera jamais une entrée sur le fichier journal mais grep silencieusement ...
la source
logfile
sinon cela pourrait prendre un temps arbitrairement long avanttail
qu'une autre ligne ne soit générée et détectée quigrep
est décédée (viaSIGPIPE
).Voici une solution bien meilleure qui ne vous oblige pas à écrire dans le fichier journal, ce qui est très dangereux, voire impossible dans certains cas.
Actuellement, il n'a qu'un effet secondaire, le
tail
processus restera en arrière-plan jusqu'à ce que la ligne suivante soit écrite dans le journal.la source
tail -n +0 -f
commence au début du fichier.tail -n 0 -f
commence à la fin du fichier.myscript.sh: line 14: 7845 Terminated sh -c 'tail...
tail
processus reste en cours d'exécution en arrière-plan.Les autres solutions ici ont plusieurs problèmes:
Voici ce que j'ai proposé d'utiliser l'exemple de tomcat (supprimez les hachages si vous voulez voir le journal pendant son démarrage):
la source
La
tail
commande peut être mise en arrière-plan et son pid renvoyé augrep
sous - shell. Dans legrep
sous - shell, un gestionnaire d'interruption sur EXIT peut tuer latail
commande.la source
Lisez-les tous. tldr: découpler la fin de tail de grep.
Les deux formes les plus pratiques sont
et si vous avez bash
Mais si cette queue assise à l’arrière-plan vous dérange, il ya une solution plus agréable qu’un fifo ou toute autre réponse. Nécessite bash.
Ou si ce n'est pas la queue qui produit des choses,
la source
Essayez d'utiliser inotify (inotifywait)
Vous configurez inotifywait pour tout changement de fichier, puis vérifiez le fichier avec grep. S'il ne le trouve pas, relancez-le inotifywait. Si vous le trouvez, quittez la boucle ... Smth like that
la source
$!
; inotifywait -e MODIFY / tmp / trouvé; kill -KILL - $ MYPIDVous voulez partir dès que la ligne est écrite, mais vous voulez aussi partir après un délai d'attente:
la source
que dis-tu de ça:
bien que vrai faire si [! -z $ (grep "myRegEx" myLog.log)]; puis pause Fi ; terminé
la source