Renvoie uniquement la partie d'une ligne après un motif correspondant

109

Donc ouvrir un fichier avec cat, puis utiliser greppour obtenir les lignes correspondantes ne me fait avancer que lorsque je travaille avec le jeu de journaux particulier que je traite. Il faut un moyen de faire correspondre les lignes à un motif, mais seulement de renvoyer la partie de la ligne après la correspondance. La partie avant et après le match variera de manière constante. J'ai joué avec using sedou awk, mais je n'ai pas réussi à comprendre comment filtrer la ligne pour supprimer la partie avant le match ou simplement pour renvoyer la partie après le match, cela fonctionnera. Voici un exemple de ligne que je dois filtrer:

2011-11-07T05:37:43-08:00 <0.4> isi-udb5-ash4-1(id1) /boot/kernel.amd64/kernel: [gmp_info.c:1758](pid 40370="kt: gmp-drive-updat")(tid=100872) new group: <15,1773>: { 1:0-25,27-34,37-38, 2:0-33,35-36, 3:0-35, 4:0-9,11-14,16-32,34-38, 5:0-35, 6:0-15,17-36, 7:0-16,18-36, 8:0-14,16-32,34-36, 9:0-10,12-36, 10-11:0-35, 12:0-5,7-30,32-35, 13-19:0-35, 20:0,2-35, down: 8:15, soft_failed: 1:27, 8:15, stalled: 12:6,31, 20:1 }

La partie dont j'ai besoin est tout après "bloquée".

Le contexte derrière ceci est que je peux savoir combien de fois quelque chose cale:

cat messages | grep stalled | wc -l

Ce que je dois faire est de savoir combien de fois un certain nœud a bloqué (indiqué par la partie précédant chaque signe deux-points après "bloqué". Si je ne fais que grep pour cela (c'est-à-dire 20 :), il peut renvoyer les lignes dont le logiciel échoue, mais pas de décrochage, ce qui ne m'aide pas. Je dois filtrer uniquement la partie bloquée afin de pouvoir ensuite rechercher un noeud spécifique parmi ceux qui sont bloqués.

À toutes fins pratiques, il s’agit d’un système freebsd avec les utilitaires standard GNU, mais je ne peux rien installer d’aide supplémentaire.

MaQleod
la source
@ Gilles, Odd, comment cela ne s'est pas produit lorsque j'ai cherché, même si je n'ai pas utilisé le titre avec lequel je suis finalement allé ... mais il n'apparaissait pas à l'écran sous mon titre. Quoi qu'il en soit, cela mis à part, cela pourrait me mener là où je veux, même si j'ai besoin de toute la ligne après le match, pas du premier mot - mais cela ne prendra peut-être pas grand chose.
MaQleod
Son titre était nul. J'ai volé le tien qui est très gentil. Prenez la sedsolution et ne traitez pas les espaces en particulier.
Gilles
@ Gilles, c'est quelque chose que je ne sais pas trop comment faire. J'apprends encore sed.
MaQleod
similaire à unix.stackexchange.com/questions/24089/… ainsi.
Tim Kennedy
1
@ shaa0601 Je ne comprends pas votre question, il est particulièrement difficile de suivre un commentaire sans mise en forme. Posez une nouvelle question autonome.
Gilles

Réponses:

142

L'outil canonique pour cela serait sed.

sed -n -e 's/^.*stalled: //p'

Explication détaillée:

  • -n signifie ne rien imprimer par défaut.
  • -e est suivi d'une commande sed.
  • s est la commande de remplacement de modèle.
  • L'expression régulière ^.*stalled:correspond au modèle que vous recherchez, plus tout texte précédent ( .*ce qui signifie n'importe quel texte, avec une initiale ^pour indiquer que la correspondance commence au début de la ligne). Notez que si stalled:se produit plusieurs fois sur la ligne, cela correspond à la dernière occurrence.
  • La correspondance, c'est-à-dire tout ce qui est sur la ligne jusqu'à stalled:, est remplacée par la chaîne vide (c'est-à-dire supprimée).
  • Le dernier pmoyen d'imprimer la ligne transformée.

Si vous souhaitez conserver la partie correspondante, utilisez une référence arrière: \1dans la pièce de remplacement, indiquez ce qui se trouve à l'intérieur d'un groupe \(…\)dans le motif. Ici, vous pourriez écrire à stalled:nouveau dans la pièce de rechange; cette fonctionnalité est utile lorsque le motif recherché est plus général qu'une simple chaîne.

sed -n -e 's/^.*\(stalled: \)/\1/p'

Parfois, vous voudrez supprimer la partie de la ligne après le match. Vous pouvez l'inclure dans la correspondance en ajoutant .*$à la fin du motif (tout texte .*suivi de la fin de la ligne $). Sauf si vous placez cette partie dans un groupe que vous avez référencé dans le texte de remplacement, la fin de la ligne ne sera pas dans la sortie.

Pour illustrer davantage les groupes et les références arrière, cette commande permute la partie avant le match et la partie après le match.

sed -n -e 's/^\(.*\)\(stalled: \)\(.*\)$/\3\2\1/p'
Gilles
la source
J'ai essayé les deux premiers exemples et ça a l'air de rester en suspens. Je ne reçois pas de message d'erreur ni de nouvelle invite, mais rien du tout.
MaQleod
2
@MaQleod Oh, il attend l'entrée sur l'entrée standard, voici le terminal car vous ne l'avez pas redirigé. Ici, vous feriez une redirection d'entrée sed … <messages, car vous voulez traiter les données d'un fichier. Pour agir sur les données produites par une autre commande, vous utiliseriez un tuyau: somecommand | sed ….
Gilles
1
à droite, panne de courant de fin de journée là-bas. commande fonctionne parfaitement, merci.
MaQleod
1
Meilleure explication sed que j'ai vue jusqu'à présent - merci!
Jon Wadsworth
1
@ungalcrys Version plus courte de quoi? Ce n'est équivalent à aucune des commandes de ma réponse. Je vous recommande de l'écrire sed 's/^.*stalled//'car -rétant spécifique à Linux et ne fonctionnant pas sur d'autres systèmes tels que macOS, vous n'en tirez aucun avantage.
Gilles
73

L'autre outil canonique que vous utilisez déjà grep:

Par exemple:

grep -o 'stalled.*'

A le même résultat que la deuxième option de Gilles:

sed -n -e 's/^.*\(stalled: \)/\1/p'

Le -odrapeau renvoie la --only-matchingpartie de l'expression, donc pas la ligne entière qui est - bien sûr - normalement faite par grep.

Pour supprimer le "calé:" de la sortie, nous pouvons utiliser un troisième outil canonique, couper:

grep -o 'stalled.*' | cut -f2- -d:

La cutcommande utilise le délimiteur :et imprime le champ 2 jusqu'à la fin. C'est une question de préférence bien sûr, mais la cutsyntaxe est très facile à retenir.

Anne van Rossum
la source
2
Merci d'avoir mentionné l' -ooption! Je voulais souligner que grepne reconnaît pas le caractère \nde nouvelle ligne. Votre premier exemple ne correspond donc qu'au premier ncaractère. Par exemple, echo "Hello Anne" | grep -o 'A[^\n]*'renvoie la chaîne A. Cependant, echo "Hello Anne" | grep -o 'A.*'retourne l'attendu Anne, puisqu'il .correspond à n'importe quel caractère sauf la nouvelle ligne.
Adamlamar
1
Notez que les guillemets autour du cutdélimiteur -d':'sont supprimés par @poige. Je trouve plus facile de me souvenir avec des citations, par exemple avec -d' 'ou -d';'.
Anne van Rossum
Selon vos conclusions, il devrait être plus facile de vous rappeler d’utiliser des citations -f 2aussi. Sérieusement, pourquoi pas?
poige
Parce qu'un délimiteur comme un point-virgule ;plutôt que deux-points :sera interprété différemment s'il n'est pas cité. Bien sûr, c'est un comportement logique, mais j'aime quand même m'appuyer sur la mémoire musculaire. Je n'aime pas citer le délimiteur une fois mais pas l'autre fois. Juste préférence personnelle, comme je l'ai dit auparavant: plus facile à retenir.
Anne van Rossum
la période qui fait partie de la .*est nécessaire, a bien fonctionné pour moi: cat filename | grep 'Return only this line xyz text' | grep -o 'xyz.*' retoursxyz text
ron
4

Je ifconfig | grep eth0 | cut -f3- -d:prenais ça

    [root@MyPC ~]# ifconfig
    eth0  Link encap:Ethernet  HWaddr AC:B4:CA:DD:E6:F8
          inet addr:192.168.0.2  Bcast:192.168.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:78998810244 errors:1 dropped:0 overruns:0 frame:1
          TX packets:20113430261 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:110947036025418 (100.9 TiB)  TX bytes:15010653222322 (13.6 TiB)

et le faire ressembler à ceci

    [root@MyPC ~]# ifconfig | grep eth0 | cut -f3- -d:
    C4:7A:4D:F6:B8
Luis Perez
la source
2
Est-ce que cela répond à la question?
Stephen Rauch
1
Vous pouvez utiliser cat /sys/class/net/*/address, aucune analyse requise.
Anne van Rossum
1

Encore un autre outil canonique que vous avez considéré awkpourrait être utilisé avec la ligne suivante:

awk -F"stalled" '/stalled/{print $2}' messages

Explication détaillée:

  • -Fdéfinit un séparateur pour la ligne, c'est-à-dire "calé". Tout ce qui se trouve avant le séparateur est traité avec $1et tout ce qui suit est traité avec $2.
  • /reg-ex/ Recherche l'expression régulière correspondante, dans ce cas "stalled".
  • {print $<n>}- imprime n colonne. Puisque votre séparateur est défini comme bloqué, tout ce qui suit est considéré comme la deuxième colonne.
robertm.tum
la source