Rechercher un motif et imprimer les lignes précédentes en commençant par un autre motif

J'ai besoin de grep pour un motif et une fois que je le trouve, j'ai besoin de chercher un autre motif précédent et d'imprimer toutes ces lignes entre ces deux.

Meilleur exemple:

1 a 2 a 3 a 4 a 5 a 6 b 7 c 8 d 9 xyz 10 xyz 11 a 12 a 

Grep pour xyz et puis grep pour d'abord a ligne xyz précédente et imprimer toutes les lignes.

Sortie (première occurrence précédente d' a , je ne m'inquiète pas des autres a dans le file):

 5 a 6 b 7 c 8 d 9 xyz 10 xyz 

Voici une solution en Perl:

 perl -nlE ' if (/a/) { @buffer = ($_) } elsif (/xyz/) { push @buffer,$_; say for @buffer } else { push @buffer,$_} ' your_file 

Comment cela fonctionne

Il lit le file ligne par ligne et fait l'une des trois choses suivantes:

  1. Si la ligne courante correspond au motif a , elle affecte la ligne courante au tableau @buffer .
  2. Si la ligne actuelle correspond au motif xyz , elle pousse la ligne courante sur la memory tampon et imprime le contenu de la memory tampon
  3. Si aucun des deux cas ci-dessus n'est vrai, il ajoute simplement la ligne courante au tableau @buffer .

Ainsi, chaque fois qu'une nouvelle ligne correspond au motif a , le contenu du @buffer est effacé et remplacé par la ligne courante seulement. Cela garantit que vous findez le plus proche a xyz précédent.

Vous devriez bien sûr replace les expressions rationnelles que j'ai utilisées avec les expressions rationnelles pertinentes à votre cas.

Je pense que tu pourrais faire quelque chose comme

 grep -zPo '.*a(?s)(?(?!a).)*?xyz' file 

(avec GNU grep, si votre version est assez récente pour prendre en charge l'extension PCRE) ou

 pcregrep -Mo '.*a(?s)(?(?!a).)*?xyz' file 

Si vous voulez faire correspondre à la deuxième instance de xyz dans votre sortie, rendre la correspondance avide en supprimant la finale ? par exemple grep -zPo '.*a(?s)(?(?!a).)*xyz' file .


Peut-être un meilleur test est-ce, avec des templates multi-caractères pour la condition de départ et d'arrêt; donné

 $ cat file 1 abc 2 abc 3 abc 4 abc 5 abc 6 bbc 7 cbc 8 dbc 9 xyz 10 xyz 11 abc 12 abc 

puis

 $ grep -zPo '.*abc(?s)(?(?!abc).)*?xyz' file 5 abc 6 bbc 7 cbc 8 dbc 9 xyz 
 tac file | sed '/xyz/,/a/!d' | tac 

(si vous n'avez pas tac , votre command tail peut avoir une command -r pour faire la même chose).

Si vous ne vous souciez pas des lignes vides dans la sortie, essayez:

 $ awk ' !NF { next } /a/ { flag = 1; last = $0; next } last && flag { print last; print; last = 0; next} /xyz/ { print; flag = 0; next} flag ' file 5 a 6 b 7 c 8 d 9 xyz 10 xyz