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

gdw2
la source
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.

choroba
la source
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.

math
la source
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éé
Blake Regalia
la source
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.)

Keith Thompson
la source
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.

Joanis
la source