Voici une autre façon avec sed
:
sed '/foo/,$!d;H;/bar/!d;s/.*//;x;s/\n//' infile
Il ajoute chaque ligne de la /foo/,$
plage (les lignes !
ne faisant pas partie de cette plage sont d
supprimées) à l' H
ancien espace. Les lignes qui ne correspondent pas bar
sont ensuite supprimées. Sur les lignes qui correspondent, l'espace de motif est vidé, e x
changé avec l'espace de maintien et la ligne vide de tête dans l'espace de motif est supprimée.
Avec une entrée énorme et peu d'occurrences, bar
cela devrait être (beaucoup) plus rapide que de tirer chaque ligne dans l'espace de motif et, à chaque fois, de vérifier l'espace de motif bar
.
Expliqué:
sed '/foo/,$!d # delete line if not in this range
H # append to hold space
/bar/!d # if it doesn't match bar, delete
s/.*// # otherwise empty pattern space and
x # exchange hold buffer w. pattern space then
s/\n// # remove the leading newline
' infile
Bien sûr, s'il s'agit d'un fichier (et qu'il tient en mémoire), vous pouvez simplement exécuter:
ed -s infile<<'IN'
.t.
/foo/,?bar?p
q
IN
car ed
peut rechercher en avant et en arrière.
Vous pouvez même lire une sortie de commande dans le tampon de texte si votre shell prend en charge la substitution de processus:
printf '%s\n' .t. /foo/,?bar?p q | ed -s <(your command)
ou si ce n'est pas le cas, avec gnu ed
:
printf '%s\n' .t. /foo/,?bar?p q | ed -s '!your command'
foo
et le dernierbar
et imprimez tout le reste , le cas échéant. Avec un flux, vous devrez lire jusqu'au premierfoo
et mettre en mémoire tampon toutes les lignes suivantes jusqu'à EOF, en vidant le tampon chaque fois que abar
est vu. Cela pourrait signifier la mise en mémoire tampon de l'ensemble du flux en mémoire.