Come selezionare le linee tra due pattern di marker che possono verificarsi più volte con awk / sed

Usando awk o sed come posso selezionare le linee che si verificano tra due diversi pattern di marker? Potrebbero esserci più sezioni contrassegnate con questi modelli.

Ad esempio: Supponiamo che il file contenga:

 abc def1 ghi1 jkl1 mno abc def2 ghi2 jkl2 mno pqr stu 

E il modello iniziale è abc e il pattern finale è mno Quindi, ho bisogno dell’output come:

 def1 ghi1 jkl1 def2 ghi2 jkl2 

Sto usando sed per abbinare il modello una volta:

 sed -e '1,/abc/d' -e '/mno/,$d'  

C’è un modo in sed o awk di farlo ripetutamente fino alla fine del file?

Utilizza awk con un flag per triggersre la stampa quando necessario:

 $ awk '/abc/{flag=1;next}/mno/{flag=0}flag' file def1 ghi1 jkl1 def2 ghi2 jkl2 

Come funziona?

  • /abc/ corrisponde alle righe che hanno questo testo, così come /mno/ does.
  • /abc/{flag=1;next} imposta il flag quando viene trovato il testo abc . Quindi, salta la linea.
  • /mno/{flag=0} distriggers il flag quando viene trovato il testo mno .
  • Il flag finale è un pattern con l’azione di default, che è di print $0 : se flag è uguale a 1 la linea viene stampata.

Per una descrizione più dettagliata ed esempi, insieme ai casi in cui i modelli sono mostrati o meno, vedi Come selezionare le linee tra due modelli? .

Usando sed :

 sed -n -e '/^abc$/,/^mno$/{ /^abc$/d; /^mno$/d; p; }' 

L’opzione -n significa che non viene stampata di default.

Il modello cerca le linee che contengono solo abc appena a mno , quindi esegue le azioni nel { ... } . La prima azione cancella la linea abc ; il secondo la linea mno ; e la p stampa le righe rimanenti. È ansible rilassare le espressioni rege come richiesto. Qualsiasi linea al di fuori del range di abc .. mno viene semplicemente stampata.

Questo potrebbe funzionare per te (GNU sed):

 sed '/^abc$/,/^mno$/{//!b};d' file 

Elimina tutte le righe tranne quelle tra le righe che iniziano con abc e mno

 sed '/^abc$/,/^mno$/!d;//d' file 

golf due personaggi meglio di ppotong {//!b};d

Le barre vuote in avanti // significano: “riusare l’ultima espressione regolare usata”. e il comando fa lo stesso di quello più comprensibile:

 sed '/^abc$/,/^mno$/!d;/^abc$/d;/^mno$/d' file 

Questo sembra essere POSIX :

Se un RE è vuoto (cioè non è specificato alcun modello) sed si comporterà come se fosse stata specificata l’ultima RE utilizzata nell’ultimo comando applicato (come indirizzo o parte di un comando sostitutivo).

Dai link della precedente risposta, quello che ha fatto per me, eseguire ksh su Solaris, era questo:

 sed '1,/firstmatch/d;/secondmatch/,$d' 

La risposta di Don_crissti da Mostra solo il testo tra 2 pattern di corrispondenza ?

 firstmatch="abc" secondmatch="cdf" sed "/$firstmatch/,/$secondmatch/!d;//d" infile 

che è molto più efficiente dell’applicazione di AWK, vedi qui .

 perl -lne 'print if((/abc/../mno/) && !(/abc/||/mno/))' your_file 

qualcosa del genere funziona per me:

file.awk:

 BEGIN { record=0 } /^abc$/ { record=1 } /^mno$/ { record=0; print "s="s; s="" } !/^abc|mno$/ { if (record==1) { s = s"\n"$0 } } 

utilizzando: awk -f file.awk data

modifica: O_o la soluzione fedorqui è decisamente migliore / più carina della mia.