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:
a
, elle affecte la ligne courante au tableau @buffer
. xyz
, elle pousse la ligne courante sur la memory tampon et imprime le contenu de la memory tampon @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