"Regarder" la sortie d'une commande jusqu'à ce qu'une chaîne particulière soit observée, puis quitter


29

Je cherche un moyen de regarder par programmation la sortie d'une commande jusqu'à ce qu'une chaîne particulière soit observée, puis de quitter. C'est très similaire à cette question, mais au lieu de suivre un fichier, je veux «suivre» une commande.

Quelque chose comme:

montre -n1 my_cmd | grep -m 1 "String Im Looking For"

(Mais cela ne fonctionne pas pour moi.)

MISE À JOUR: J'ai besoin de préciser que 'my_cmd' ne produit pas de texte en continu mais doit être appelé à plusieurs reprises jusqu'à ce que la chaîne soit trouvée (c'est pourquoi j'ai pensé à la commande 'watch'). À cet égard, 'my_cmd' est comme de nombreuses autres commandes Unix telles que: ps, ls, lsof, last, etc.


J'aurais pensé qu'il était possible de tail -fsortir un programme aussi bien qu'un fichier ... Je me trompe?
Joanis

@Joanis. Vous avez raison, mais dans mon cas, 'my_cmd' ne produit pas de sortie en continu et doit être appelé à plusieurs reprises (un peu comme la plupart des commandes: ps, ls, lsof, etc.)
gdw2

Réponses:


41

Utilisez une boucle:

until my_cmd | grep -m 1 "String Im Looking For"; do : ; done

Au lieu de :, vous pouvez utiliser sleep 1(ou 0,2) pour alléger le processeur.

La boucle s'exécute jusqu'à ce que grep trouve la chaîne dans la sortie de la commande. -m 1signifie "une seule correspondance suffit", c'est-à-dire que grep arrête la recherche après avoir trouvé la première correspondance.

Vous pouvez également utiliser grep -qce qui se ferme également après avoir trouvé la première correspondance, mais sans imprimer la ligne correspondante.


une explication de cette commande serait appréciée.
Mark W

@MarkW: mis à jour.
choroba

quelqu'un d'autre a mentionné grep -qce qui est une autre option. grep se ferme après avoir trouvé la chaîne.
Sun

notez que cette commande exécutera à plusieurs reprises la commande en question, ce qui pourrait être souhaitable ou non.
adrien

1
@A__: C'est souhaitable, comme indiqué dans le PO sous "Mise à jour".
choroba

11
watch -e "! my_cmd | grep -m 1 \"String Im Looking For\""
  • ! annule le code de sortie du pipeline de commandes
  • grep -m 1 se ferme lorsque la chaîne est trouvée
  • watch -e renvoie si une erreur s'est produite

Mais cela peut être amélioré pour afficher réellement cette ligne correspondante, qui est jetée jusqu'à présent.


Merci pour l'explication détaillée, mais cela ne fonctionne pas pour moi. Ma watchcommande (CentOS) n'a pas le -edrapeau (ce qui ne devrait pas vraiment avoir d'importance). Plus important encore, cependant, lorsque la chaîne est trouvée, watch continue de s'exécuter et ne se ferme pas. Il semble que quand on grep -msort, ça ne fait que tuer my_cmd, mais pas watch.
gdw2

Non, c'est important!, Le drapeau "-e" est utilisé pour quitter la veille lorsque la commande a un code d'erreur différent de 0. Comme sa veille n'est pas sur le point de continuer sur votre plate-forme. Quoi qu'il en soit, bon à savoir, sur mon installation Ubuntu 11.10, tout va bien. J'ai également parfois des problèmes avec Mac OSX concernant des outils de ligne de commande très très obsolètes et j'utilise des ports mac jusqu'à présent pour obtenir des logiciels plus récents.
math

Cela s'arrête si le motif est trouvé, mais il n'affiche aucune sortie jusqu'à ce que cela se produise
Mark

Vous pouvez utiliser teepour cela, mais cela introduit une nouvelle ligne trompeuse, je ne sais pas comment contourner en ce moment:watch -n1 -e "! date | tee /dev/tty | grep --color -m 1 \"17\""
math

Ouais, ça n'a pas marché pour moi. watcharrête consciencieusement de regarder quand la chaîne est trouvée, mais elle ne se termine pas tant que vous n'appuyez pas sur une touche. Si proche.
mlissner

8

Pour ceux qui ont un programme qui écrit continuellement sur stdout, tout ce que vous avez à faire est de le diriger vers grep avec l'option 'single match'. Une fois que grep trouve la chaîne correspondante, il se ferme, ce qui ferme stdout sur le processus en cours de transmission vers grep. Cet événement doit naturellement provoquer la fermeture du programme sans problème tant que le processus réécrit .

Ce qui se passera, c'est que le processus recevra un SIGPIPE lorsqu'il essaiera d'écrire dans stdout fermé après la fin de grep. Voici un exemple avec ping, qui autrement fonctionnerait indéfiniment:

$ ping superuser.com | grep -m 1 "icmp_seq"

Cette commande correspondra au premier «pong» réussi, puis quittera la prochaine fois qu'il pingessaiera d'écrire sur stdout.


cependant,

Il n'est pas toujours garanti que le processus réécrira sur stdout et ne provoquera donc pas la génération d'un SIGPIPE (par exemple, cela peut se produire lors de la personnalisation d'un fichier journal). La meilleure solution que j'ai réussi à trouver pour ce scénario consiste à écrire dans un fichier; veuillez commenter si vous pensez pouvoir améliorer:

$ { tail -f log_file & echo $! > pid; } | { grep -m1 "find_me" && kill -9 $(cat pid) && rm pid; }

Décomposer cela:

  1. tail -f log_file & echo $! > pid- conserve un fichier, attache le processus à l'arrière-plan et enregistre le PID ( $!) dans un fichier. J'ai plutôt essayé d'exporter le PID vers une variable, mais il semble qu'il y ait une condition de concurrence entre ici et le moment où le PID est à nouveau utilisé.
  2. { ... ;}- regrouper ces commandes afin que nous puissions diriger la sortie vers grep tout en gardant le contexte actuel (aide lors de l'enregistrement et de la réutilisation des variables, mais n'a pas pu faire fonctionner cette partie)
  3. | - diriger la sortie du côté gauche vers la sortie du côté droit
  4. grep -m1 "find_me" - trouver la chaîne cible
  5. && kill -9 $(cat pid)- force kill (SIGKILL) le tailprocessus après la grep sortie une fois qu'il trouve la chaîne correspondante
  6. && rm pid - supprimez le fichier que nous avons créé

0
my_cmd | tail +1f | sed '/String Im Looking For/q'

Si tailne prend pas en charge la +1fsyntaxe, essayez tail -f -n +1. (Le lui -n +1indique de commencer au début; tail -fpar défaut commence par les 10 dernières lignes de sortie.)


Veuillez consulter ma mise à jour de la question.
gdw2

0

Ajoutez le résultat de vos appels de programme à un fichier. Ensuite, tail -fce fichier. De cette façon, cela devrait fonctionner ... j'espère.

Lorsque vous recommencerez à appeler ce programme, vous devrez effacer le fichier ou y ajouter du charabia juste pour qu'il ne corresponde pas tout de suite à ce que vous cherchiez.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.