8
votes

Saisir la nième occurrence entre deux motifs utilisant awk ou sed

J'ai un problème dans lequel je veux analyser à travers la sortie à partir d'un fichier et que je souhaite saisir la nième occurrence de texte entre deux modèles de préférence en utilisant AWK ou SED

category
3
r
d
done


1 commentaires

Dans quelle partie de cela avez-vous des problèmes? Avez-vous du code que vous avez essayé cela ne fonctionne pas?


5 Réponses :


7
votes

Essayez de faire ceci: xxx pré>

ou plus cryptique: p> xxx pré>

si votre fichier est grand: p>

awk -v n=3 '/^category/{l++} l>n{exit} l==n' file.txt


3 commentaires

Désolé, disons que le début et la fin ne sont pas le même mot, je veux que la troisième occurrence de ce qui entre entre catégorie et fait.


/ ^ Catégorie / Moyenne d'une chaîne commençant par "Catégorie", c'est vraiment différent d'une ligne contenant catégorie. Donc, aucun besoin de modification, le script fonctionne toujours tel quel.


Cela fonctionnera avec l'entrée d'échantillon affichée, mais ne fonctionnera pas s'il y a eu des occurrences de catégorie sans effectuer ou de textos entre la catégorie et la catégorie.



2
votes

Si votre fichier ne contient pas de caractères NULL, voici en bonne voie avec gnu sed code>. Cela trouvera l'occurrence troisième em> d'une plage de motifs. Cependant, vous pouvez facilement modifier cela pour obtenir n'importe quel événement que vous souhaitez. XXX PRE>

Résultats: P>

category
3
r
d
done


1 commentaires

J'aimerais imprimer la 3ème occurrence, mais seulement si la 2e occurrence contenait le mot "awk". Comment puis-je modifier cette commande SED pour faire cela? Dans Awk, je créerais simplement une variable "PrevRec" pour stocker l'enregistrement précédent et ajouter un si (prevec ~ / awk /) avant l'impression.



8
votes

Ceci pourrait fonctionner pour vous (GNU SED): xxx pré>

désactiver l'impression automatique à l'aide de l'option -n code>. Rassemblez des lignes entre catégorie code> et effectué code>. Conservez un compteur dans l'espace de maintien et lorsqu'il atteint 3 impression de la collection dans l'espace motif et quittez-le. P>

ou si vous préférez AWK: P>

awk  '/^category/,/^done/{if(++m==1)n++;if(n==3)print;if(/^done/)m=0}'  file


7 commentaires

Sed est un excellent outil pour des substitutions simples sur une seule ligne. Pour autre chose, utilisez simplement AWK ou vous trouverez que le changement d'exigences les plus minifères (par exemple, imprimer les numéros de ligne) nécessite une réécriture totale de votre script, éventuellement dans une langue différente. Faire n'importe quoi dans SED qui nécessite plus que des commandes "s" et "g" est une perte de temps.


Le script AWK continuera à l'impression après le «fait» s'il y a des TES = XT entre Tes = XT entre et la catégorie suivante. Il imprimerait également le mauvais bloc si la catégorie peut exister sans faire. Je ne sais pas ce que les scripts SED feraient.


@Edmorton Je pense que l'impression est réduite entre catégorie et effectué , s'il n'y a pas effectué Ceci peut être ce que l'utilisateur a besoin.


Essayez-le avec un fichier avec 2 lignes "catégorie" avant la première "FAIT". Il imprimera le 2e catégorie-> Block Terminé au lieu du 3ème.


J'ai utilisé cette méthode awk awk '/ ^ Catégorie /, / ^ DONE / {SI (/ ^ Catégorie /) N ++; Si (n == 3) Imprimer}' Fichier Merci pour la réponse


Juste curieux: pourquoi? Il teste le même état plusieurs fois et ne fonctionnera pas si votre fichier d'entrée change légèrement. Si vous êtes satisfait d'une solution qui fonctionne uniquement avec exactement le format d'entrée posté, la solution de Spoutnik est beaucoup plus concise.


Pouvez-vous s'il vous plaît expliquer les deux commandes SED..That sera vraiment informatif et serviable!



0
votes

avec GNU AWK Vous pouvez définir le séparateur d'enregistrement sur une expression régulière: xxx pré>

sortie: p> xxx pré>

rt code> est le séparateur d'enregistrement correspondant. Notez que l'enregistrement par rapport à N code> sera désactivé par un comme le premier enregistrement fait référence à ce qui précède le premier RS code>. P>

EDIT H3>

Selon le commentaire de ED, cela ne fonctionnera pas lorsque les enregistrements ont d'autres données entre eux, par exemple: p>

<file awk '/^category$/ { v = $0; while(!/^done$/) { if(!getline) exit; v = v ORS $0 } if(++nr == n)  print v }' n=3


7 commentaires

Cela imprimera le texte entre les occurrences de la catégorie de mots, pas entre catégorie et faite. Dans l'entrée affichée, cela n'a pas d'importance, mais en général, cela pourrait, par ex. Si f Peut y avoir d'autres textes entre Catégorie et Catégorie ou des occurrences de catégorie sans une pièce associée.


@Edmorton: vrai. Un correctif possible consiste à nettoyer l'entrée en premier, voir Modifier.


Cela échouerait toujours et imprimerait le 2e enregistrement au lieu du 3ème siècle si vous avez ajouté une ligne de "catégorie" avant le premier "Terminé" dans votre exemple d'entrée, par exemple. entre les lignes "S" et "T".


@Edmorton: Droite, je vois votre point de vue, le modèle de fin n'est pas recherché. J'ai ajouté un getline alternatif qui recherche effectué .


IMHO La version non getline I Publiée est plus simple et il n'a pas toutes les mises en garde GetLine (voir awk.info /? Conseil / goulot ). Je m'attends à ce que vous ayez posté cela, tout comme contraste avec les autres solutions, mais pour la prestation des OPS, je pense que cela mérite de mentionner explicitement que cela vient avec des bagages.


@Edmorton: En effet, je l'envisageons comme un contraste. Je n'avais pas réalisé que GetLine n'avait pas eu de nombreux problèmes potentiels, en fonction de ce que l'OP est en train de le faire ou peut ne pas être un problème. Je vais mettre un avertissement et une référence sur la réponse. Nice post au fait.


1) Merci. 2) Ouais, GetLine est une boîte de vers. C'est très utile lorsqu'il est utilisé de manière appropriée, cependant, comme une grenade à la main.



1
votes
awk -v tgt=3 '
/^category$/ { fnd=1; rec="" }

fnd {
   rec = rec $0 ORS
   if (/^done$/) {
      if (++cnt == tgt) {
         printf "%s",rec
         exit
      }
      fnd = 0
   }
}
' file

0 commentaires