2013-05-20 13 views
7

Please help me in using sed. Ho un file come di seguito.Sed per estrarre il testo tra due stringhe

START=A 
    xxxxx 
    xxxxx 
END 
START=A 
    xxxxx 
    xxxxx 
END 
START=A 
    xxxxx 
    xxxxx 
END 
START=B 
    xxxxx 
    xxxxx 
END 
START=A 
    xxxxx 
    xxxxx 
END 
START=C 
    xxxxx 
    xxxxx 
END 
START=A 
    xxxxx 
    xxxxx 
END 
START=D 
    xxxxx 
    xxxxx 
END 

Voglio ottenere il testo tra START = A, END. Ho usato la query seguente.

sed '/^START=A/,/^END/!d' input_file 

Il problema qui è, sto ottenendo

START=A 
    xxxxx 
    xxxxx 
END 
START=D 
    xxxxx 
    xxxxx 
END 

invece di

START=A 
    xxxxx 
    xxxxx 
END 

Sed trova avidamente.

Please help me in resolvng this.

Grazie in anticipo.

Posso utilizzare AWK per ottenere quanto sopra?

risposta

19
sed -n '/^START=A$/,/^END$/p' data 

L'opzione -n non stampa per impostazione predefinita; quindi lo script dice 'stampa tra la riga contenente START=A e il successivo END.

Si può anche fare con awk:

Un modello può essere costituito da due pattern separati da una virgola; in questo caso, l'azione viene eseguita per tutte le righe da un'occorrenza del primo modello attraverso un'occorrenza del secondo.

(da man awk su Mac OS X).

awk '/^START=A$/,/^END$/ { print }' data 

Data una forma modificata del file di dati nella domanda:

START=A 
    xxx01 
    xxx02 
END 
START=A 
    xxx03 
    xxx04 
END 
START=A 
    xxx05 
    xxx06 
END 
START=B 
    xxx07 
    xxx08 
END 
START=A 
    xxx09 
    xxx10 
END 
START=C 
    xxx11 
    xxx12 
END 
START=A 
    xxx13 
    xxx14 
END 
START=D 
    xxx15 
    xxx16 
END 

L'output utilizzando GNU sed o Mac OS X (BSD) sed, e l'utilizzo di GNU awk o BSD awk, è il stesso:

START=A 
    xxx01 
    xxx02 
END 
START=A 
    xxx03 
    xxx04 
END 
START=A 
    xxx05 
    xxx06 
END 
START=A 
    xxx09 
    xxx10 
END 
START=A 
    xxx13 
    xxx14 
END 

Nota come ho modificato il file di dati in modo che sia più facile vedere dove sono stampati i vari blocchi di dati ca io dal file.

Se si dispone di un requisito di uscita diverso (ad esempio 'solo il primo blocco tra START = A e FINE', o 'solo l'ultimo ...'), è necessario articolare in modo più chiaro nella domanda.

+1

Grazie per la risposta. Ho bisogno di un testo tra START = A e il prossimo END, quello sopra fornisce dati tra START = A e l'ultima END. Spero che tu abbia il mio problema. – ranganath111

+0

No, non è così. Sia gli script 'awk' che' sed' - almeno sulla mia macchina con la mia copia del file di dati che hai fornito - stampano 5 blocchi di dati tra 'START = A' e' END', ei blocchi con 'START = B' per 'END',' START = C' per 'END' e' START = D' per 'END' sono tutti omessi dall'output. Su quale piattaforma stai testando? Quale versione di 'sed' stai usando? Quale versione di 'awk' stai usando? (Prendo atto che i dati del test ripetono testualmente i blocchi tra 'START = A' e' END'. Sarebbe molto meglio se ci fossero linee diverse tra loro in modo da poter vedere quali linee vengono stampate.) –

+0

Quando provo questo , i punti di inizio e fine sono inclusi nell'output, mentre ho avuto l'impressione che l'OP volesse solo i dati TRA loro. –

2

L'espressione sed ha uno spazio prima della fine, ovvero / ^END/. Quindi sed ottiene il modello iniziale, ma non ottiene il modello finale e continua a stampare fino alla fine. Utilizzare sed '/^START=A/, /^END/!d' input_file (avviso /^END/)

+0

Buon punto sullo spazio nella regex 'sed', anche se rende l'output quotato ancora più sconcertante (come in 'Non riesco a riprodurre il cita l'output con lo script originale, ma elimina lo spazio estraneo e funziona bene, anche se cackhanded '). Puoi almeno semplificare l'ultima parte del tuo script 'awk' in'/END/{flag = 0} 'che potrebbe impostare il flag su zero quando era già zero, ma questo non fa male. Puoi anche usare '/ START = A /,/END/{print}' che è molto più semplice. –

+0

sì, '/ START = A /,/END/{print}' questo è molto più semplice, ma è già mostrato nella tua risposta :) Stavo solo giocando con una bandiera :). In realtà, dopo la soluzione "awk" che hai dato, non ha bisogno di fare altro. Toglierò la mia soluzione 'awk'. Potrebbe portare a più confusione che a fare qualcosa di buono: P – abasu

+0

sì .. Ce l'ho .. Grazie mille – ranganath111

3

Versione di base ...

sed -n '/START=A/,/END/p' yourfile 

versione più robusta ...

sed -n '/^ *START=A *$/,/^ *END *$/p' yourfile 
+0

puoi spiegare cosa ',' significa in stringa modello sed? –

+0

@Vikrant - il ',' separa due parti di un * intervallo * definito da due regex in modo che vengano restituite le linee tra il primo modello e il secondo motivo. – starfry