Voici le texte dans le fichier:

Pseudo name=Apple Code=42B state=fault Pseudo name=Prance Code=43B state=good 

Je dois grep pour « 42B » et obtenez le résultat du texte ci-dessus comme:

Pseudo name=Apple Code=42B state=fault 

Quelquun a-t-il une idée sur la façon dy parvenir en utilisant grep / awk / sed?

Commentaires

  • Vous avez tagué cette question uniquement avec " grep ". Recherchez-vous uniquement des solutions " grep "? Dans la question, vous spécifiez également awk & sed. Pouvons-nous ajouter ces balises? Je nétais ' pas sûr de votre intention lorsque jai modifié la question hier soir.
  • stackoverflow.com/ questions / 12024410 / …

Réponse

Avec awk

awk -v RS="" "/42B/" file 

RS= change le séparateur denregistrement dentrée dune nouvelle ligne à des lignes vides. Si un champ dun enregistrement contient /42B/, imprimez lenregistrement.

"" (la chaîne nulle) est une magie valeur utilisée pour représenter les lignes vides selon POSIX :

Si RS est nul, alors les enregistrements sont séparés par des séquences constituées dun <newline> plus un ou plusieurs espaces les lignes, les lignes vierges de début ou de fin ne doivent pas donner lieu à des enregistrements vides au début ou à la fin de lentrée, et un <newline> doit toujours être un séparateur de champ, quelle que soit la valeur de FS is.

Les paragraphes de sortie ne seront pas être séparés puisque le séparateur de sortie reste une seule nouvelle ligne. Pour vous assurer quil y a une ligne vide entre les paragraphes de sortie, définissez le séparateur denregistrement de sortie sur deux nouvelles lignes:

awk -v RS="" -v ORS="\n\n" "/42B/" file 

Commentaires

  • +1 pour une solution élégante. Vous navez ' pas besoin de rediriger le fichier …
  • les doigts étaient sur le pilote automatique.
  • @jasonwryan, sauf si vous avez besoin dun accès au nom de fichier dans awk (FILENAME), ' nest pas une mauvaise idée dutiliser la redirection car cela évite les problèmes de nom de fichier contenant = ou commençant par - (ou étant -), génère des messages derreur cohérents, et évite dexécuter awk ou deffectuer dautres redirections si le fichier dentrée ne peut ' être ouvert.

Réponse

En supposant que les données sont structurées de telle sorte que ce soit toujours la ligne avant et après que vous voulez, vous pouvez utiliser -A (after) et -B (before) commutateurs pour lui indiquer dinclure la 1 ligne avant le match et 1 ligne après:

$ grep -A 1 -B 1 "42B" sample.txt Pseudo name=Apple Code=42B state=fault 

Si vous voulez même nombre de lignes avant et après le terme de recherche, vous pouvez utiliser le commutateur -C (context):

$ grep -C 1 "42B" sample.txt Pseudo name=Apple Code=42B state=fault 

Si vous « aimeriez être plus strict lors de la mise en correspondance des lignes multiples, vous pouvez utiliser loutil pcregrep , pour faire correspondre un motif sur plusieurs lignes:

$ pcregrep -M "Pseudo.*\n.*42B.*\nstate.*" sample.txt Pseudo name=Apple Code=42B state=fault 

Le motif ci-dessus correspond comme suit:

  • -M – plusieurs lignes
  • "Pseudo.*\n.*42B.*\nstate.*" – correspond à un groupe de chaînes dont la première chaîne commence par le mot "Pseudo" suivi de tous les caractères jusquà la fin de la ligne \n, suivi de tous les caractères jusquà la chaîne "42B" suivi de tous les caractères jusquà une autre fin de ligne (\n), suivie de la chaîne "state" suivie de tout caractère.

Commentaires

  • -C (contexte) peut être utilisé comme raccourci, si -A et -B sont identiques.
  • @DavidBaggerman – merci. Ajouté à la réponse.
  • Pourquoi le vote un contre? Cela répond à la question.

Réponse

Le grep de certaines versions dUnix ont le drapeau -p pour « paragraphe ». Je sais que AIX le fait .

grep -p 42B <myfile> 

ferait exactement ce que vous demandez ici . YMMV et GNU grep nont pas ce drapeau.

Commentaires

  • Avoir le drapeau -p serait merveilleux. Surtout sil est utilisé avec -v afin que vous puissiez exclure des paragraphes entiers de la sortie.

Réponse

Il existe probablement un moyen tout aussi simple de le faire avec awk, mais en perl:

cat file | perl -ne "BEGIN { $/="\n\n" }; print if $_ =~ /42B/;" 

Cela dit essentiellement de diviser le fichier en morceaux délimités par des lignes vides, puis de nimprimer que les morceaux qui correspondent à votre expression régulière.

Commentaires

  • Cela peut être simplifié en utilisant des options et des raccourcis, et en perdant l utilisation inutile de cat ; perl -00 -ne 'print if /42B/' file

Réponse

Une autre solution Perl, sans ligne vide de fin:

perl -00ne "if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}" foo 

Exemple

% perl -00ne "if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}" foo Pseudo name=Apple Code=42B state=fault % cat foo Pseudo name=Apple Code=42B state=fault Pseudo name=Prance Code=43B state=good 

Commentaires

  • Ou plus court (et donc plus lisible), comme lécrit triplee dans un commentaire: perl -00 -ne 'print if /42B/' file.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *