2010-10-06 18 views
16

Desidero filtrare diverse righe prima e dopo una riga corrispondente in un file.ricerca inversa grep con contesto

Questo eliminerà la linea che io non voglio:

$ grep -v "line that i don't want" 

E questo stamperà le linee 2, prima e dopo la linea non voglio:

$ grep -C 2 "line that i don't want" 

Ma quando li combino, non filtra le 2 linee prima e dopo la linea che non desidero:

# does not remove 2 lines before and after the line I don't want: 
$ grep -v -C 2 "line that i don't want" 

Come faccio a filtrare non solo la linea che non desidero, ma anche le linee prima e dopo di essa? Sto indovinando sed sarebbe meglio per questo ...

Edit: so che questo potrebbe essere fatto in poche righe di awk/Perl/Python/Ruby/etc, ma voglio sapere se c'è un breve one-liner Potrei correre dalla riga di comando.

+1

http://superuser.com –

+0

c'è un motivo? – aaronstacy

risposta

4

dare una prova:

sed 'h;:b;$b;N;N;/PATTERN/{N;d};$b;P;D' inputfile 

È possibile variare il numero di N comandi prima che il modello di influenzare il numero di linee da eliminare.

Si potrebbe programmazione costruire una stringa contenente il numero di N comandi:

C=2 # corresponds to grep -C 
N=N 
for ((i = 0; i < C - 1; i++)); do N=$N";N"; done 
sed "h;:b;\$b;$N;/PATTERN/{N;d};\$b;P;D" inputfile 
+1

no, vuoi dire 'grep' non puoi farlo ?! c'è una ragione?è controintuitivo per me – n611x007

+0

@naxa: quando '-C' e' -v' vengono usati insieme '-C' include le righe escluse invece di escludere le righe aggiuntive. Prova questo: 'printf '% s \ n' {1..36} | grep --color -C 2 -v '^ 2.'' e vedrai che 20, 21, 28 e 29 sono inclusi invece di 18, 19, 30 e 31 esclusi. A proposito, l'opzione '-C' non è specificata da POSIX. –

+1

ah vedo. grazie mille per la tua preoccupazione e il bell'esempio ora a colori! Ho provato con -A e -B ma funzionano allo stesso modo -C. Sembrano anche essere "non-posix" ora che so cosa ho perso a cercare. – n611x007

1
awk 'BEGIN{n=2}{a[++i]=$0} 
/dont/{ 
    for(j=1;j<=i-(n+1);j++)print a[j]; 
    for(o=1;o<=n;o++)getline; 
    delete a} 
END{for(i in a)print a[i]} ' file 
+0

So che probabilmente lo sai già visto che hai più XP di me, ma potresti voler aggiungere qualche spiegazione in più del solo segmento di codice, considerando il fatto che l'OP ha richiesto una soluzione di grep, mentre offriva la tua soluzione AWK altrimenti molto valida ed estremamente utile. Grazie! –

+0

@DermotCanniffe, lol la risposta accettata è ancora più contorta usando sed. – ghostdog74

+0

Abbastanza vero. Per quanto mi piaccia sed, penso che le procedure di awk siano molto più semplici da spiegare. :) –

2

Se le linee sono tutti unici si potrebbe grep le righe che si desidera rimuovere in un file, e quindi utilizzare tale file da rimuovere le linee dall'originale, ad es

grep -C 2 "line I don't want" <A.txt> B.txt 
grep -f B.txt A.txt 
0

Penso che @ fxm27 abbia una risposta eccellente, bash-y.

Aggiungo che è possibile risolvere questo in un altro modo utilizzando egrep se si conoscessero in anticipo gli schemi delle righe successive.

command | egrep -v "words|from|lines|you|dont|want" 

che farà un "inclusivo OR", il che significa che una linea che corrisponde qualsiasi di chi sarà escluso.

0

L'ho risolto con due grep sequenziali, in realtà. Sembra molto più semplice per me.

grep -C "match" yourfile | grep -v -f - yourfile 
Problemi correlati