Cerca una stringa e stampa tutto prima e dopo in un intervallo


9

Ho questo file:

sometext1{
string1
}

sometext2{
string2
string3
}

sometext3{
string4
string5
string6
}

Voglio cercare in questo file una stringa specifica e stampare tutto prima di questa stringa fino all'apertura {e tutto ciò che segue questa stringa fino alla chiusura }. Ho provato a raggiungere questo obiettivo con sed, ma se provo a stampare tutto nella gamma, /{/,/string2/ad esempio sed stampa questo:

sometext1{
string1
}

sometext2{
string2
sometext3{
string4
string5
string6
}

Se cerco la stringa "string2" ho bisogno che l'output sia:

sometext2{
string2
string3
}

Grazie.


Bene, ora ho scoperto che ho bisogno dei numeri di riga dell'uscita nel file originale per eliminarli in seguito. Ho provato a cambiare il comando che @mikeserv ha fornito senza fortuna, sono un po 'confuso con la funzione hold di sed.
Rodrigo,

beh, accidenti, rodrigo, non l'hai detto a nessuno tranne te stesso. può essere fatto, ma è meglio farlo come grep -n '' <infile | sed .... I sedcomandi dovranno essere modificati; in particolare i bit di /indirizzo /che cercano ^ancore di cima linea. Quindi, se si sta utilizzando la mia risposta probabilmente si potrebbe fare: grep -n '' | sed 'H;/{$/h;/^[^:]*:}/x;/{\n.*PATTERN/!d'. Tutte le righe di output avranno il prefisso con i numeri di riga del file originale seguiti da due punti simili 1:sometext1{\n2:string1e così via. sedfiltrerà solo ciò che filtrerebbe prima, tranne per il fatto che ogni riga di output si apre con un numero.
Mikeserv,

Risposte:


9

Ecco due comandi. Se vuoi un comando che tagli fino all'ultima .*{$riga di una sequenza (come fa @don_crissti ed) puoi fare:

sed 'H;/{$/h;/^}/x;/{\n.*PATTERN/!d'

... che funziona aggiungendo ogni riga al Hvecchio spazio seguendo un \ncarattere di ewline, sovrascrivendo il hvecchio spazio per ogni riga corrispondente {$e scambiando gli hspazi vecchi e di pattern per ogni riga corrispondente ^}- e quindi svuotando il suo buffer.

Stampa solo linee che corrispondono a {quindi una \newline e poi PATTERNad un certo punto - e ciò accade sempre e solo immediatamente dopo uno scambio di buffer.

Elimina tutte le righe di una serie di {$corrispondenze all'ultima della sequenza, ma puoi ottenere tutte quelle incluse come:

sed '/PATTERN.*\n/p;//g;/{$/,/^}/H;//x;D'

Ciò che fa è scambiare pattern e hvecchi spazi per ogni ...{$.*^}.*sequenza, aggiungere tutte le linee all'interno della sequenza allo Hspazio vecchio seguendo un \ncarattere di Dewline ed elimina fino al primo \ncarattere di ewline che si verifica nello spazio di pattern per ogni ciclo di linea prima di ricominciare con ciò che rimane.

Ovviamente, l'unica volta in cui viene mai visualizzata la \newline nello spazio modello è quando una riga di input corrisponde ^}- la fine dell'intervallo - e quindi quando esegue nuovamente lo script in qualsiasi altra occasione, inserisce semplicemente la riga di input successiva come al solito.

Quando PATTERNsi trova nello stesso spazio modello di una \newline, tuttavia, stampa il lotto prima di sovrascriverlo di ^}nuovo (in modo da poter terminare l'intervallo e svuotare il buffer) .

Dato questo file di input (grazie don) :

sometext1{
string1
}

sometext2{
PATTERN
string3
}

sometext3{
string4
string5
string6
}

Header{
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}
}

Le prime stampe:

sometext2{
PATTERN
string3
}
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}

... e il secondo ...

sometext2{
PATTERN
string3
}
Header{
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}

@don_crissti - Non lo so. E ' solo delimita la sequenza per una linea che inizia con }. Questo potrebbe essere utile per ... open{\nsub;\n{ command; }\n}; close- Ma non sono sicuro che sia quello che sta succedendo qui ...
Mikeserv,

Ciao @mikeserv - Ho una domanda simile che viene sollevata qui unix.stackexchange.com/questions/232509/… , la tua soluzione funziona su file di piccole dimensioni, ma ho un file di grandi dimensioni e sto ricevendo "Spazio di spazio traboccato". messaggio di errore. Qualche possibilità sai, come potrei risolverlo?
Mille

@NarayanAkhade - no. non senza revisione, comunque. a meno che ... ci siano ampie distese di input che non sono contenute con i {...}blocchi? Se questo è il caso e stai usando la prima soluzione, potresti farlo /{$/,/^}/Hall'inizio invece che semplicemente H. Ma se hai provato anche la seconda soluzione e hai ancora riscontrato lo stesso errore, non è probabile che ti aiuti perché quello lo fa già. E non scartare edneanche. don ha una risposta molto buona qui, e edpuò essere applicato anche per usare file buffer temporanei in modo molto semplice, il che dovrebbe impedire sovraccarichi del buffer mem.
Mikeserv,

6

Ecco una soluzione con ed:

ed -s filename <<< $'g/PATTERN/?{?,/}/p\nq\n'

questo è:

g/PATTERN/     # mark each line matching PATTERN  
?{?,/}/p       # for each marked line, print all lines from the previous { up to the next }  
q              # quit editor

Questo presuppone che ci sia solo una riga PATTERNtra ogni coppia { }altrimenti si otterrà un output duplicato per ogni riga aggiuntiva PATTERNall'interno dello stesso blocco.
Funzionerà per multipli { }contenenti una corrispondenza a riga singola, PATTERNad esempio per un file di test con PATTERNin due diverse sezioni:

sometext1{
string1
}

sometext2{
PATTERN
string3
}

sometext3{
string4
string5
string6
}

Header{
sometext4{
some string

string unknown

here's PATTERN again

another string here
}
}

in esecuzione

ed -s sample <<< $'g/PATTERN/?{?,/}/p\nq\n'

uscite:

sometext2{
PATTERN
string3
}
sometext4{
some string

string unknown

here's PATTERN again

another string here
}

Ho preso molto da questo, in realtà! Grazie mille!
Mikeserv,

Non so nemmeno che questo comando esista. Grazie
rodrigo il

4

Con pcregrep:

pcregrep -M '(?s)\{[^}]*PATTERN.*?\}'

O con GNU grepfornito, l'input non contiene byte NUL:

grep -Poz '.*(?s)\{[^}]*PATTERN.*?\}'

0
$ awk 'BEGIN{RS="\n\n"; FS="[{}]"} {if ($2 ~ /string4/) {print $2}}' t1.txt
string4
string5
string6

dove:

  • string4 -> stringa da abbinare
  • t1.txt -> contiene il contenuto del file menzionato nella query

-2

sed -n '/ string / p' nomefile

the -n quando aggiunta a sed ha soppresso il comportamento predefinito di sed questa affermazione potrebbe non darti esattamente quello che vuoi ma dovrebbe semplicemente spostare la stringa

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.