2013-04-17 17 views
8

Devo cercare un file per una stringa, rimuovere qualsiasi riga che contiene la stringa e anche rimuovere le due righe che seguono qualsiasi riga che contiene la stringa. Speravo che potrei fare questo usando qualcosa di simile ...Combinazione di flag -v e -A flag in grep

$ grep -v -A 2 two temp.txt 
one 
five 
$ 

... ma purtroppo questo non ha funzionato. C'è un semplice posso farlo con grep o un altro comando di shell?

risposta

5

le seguenti opere, sia con GNU sed e con OS X.

$ sed '/two/{N;N;d;}' temp.txt 
one 
five 
  • linea ritrovamento corrispondenza two
  • letto nelle altre due linee
  • eliminarli
+0

Sia la tua risposta sia quella di @ JohnKugelman sono concise, entrambe funzionano su GNU/Linux, e non funzionano su OS X (non è un grosso problema per me per questo particolare compito). Per fornire una breve spiegazione della sintassi, la risposta accettata va a voi. Grazie. –

+2

Aggiungere un punto e virgola dopo il d e. Applica il rinforzo e dovrebbe funzionare anche su MacOS X. –

2

con GNU sed:

sed '/two/,+2d' temp.txt 

Questo utilizza la sintassi a due indirizzi (addr1,addr2) per far corrispondere le righe con la parola due (/two/) più le due righe dopo (+2). Il comando d cancella quelle linee.

+0

L'unica cosa che posso pensare è che forse stanno usando un vecchio, non GNU sed, senza l'opzione '+ number'. Ma dal momento che funziona (e non mi piacciono i downdent drive-by), ecco un voto per invertirlo. – paxdiablo

3

È possibile farlo con awk, secondo il seguente trascrizione:

pax> echo 'one 
two 
three 
four 
five' | awk '/two/ {skip=3} skip>0 {skip--;next} {print}' 

one 
five 

Si inizia fondamentalmente un contatore di righe da buttare via (3) ogni volta che trova la stringa two su una linea. Quindi getta via quelle linee finché il contatore salta non raggiunge lo zero. Ogni riga che non è contrassegnata per saltare è stampata.

+0

Questo ha il vantaggio di gestire correttamente "uno due tre due tre quattro cinque" → "uno cinque". –

1

Ecco un modo per farlo con Perl:

$ perl -ne'if (/two/){$x=<>;$x=<>;}else{print}' temp.txt 
one 
five 

Il -n è un loop implicita sopra l'ingresso. Se corrisponde a /two/, quindi leggi le due righe successive, altrimenti stampa la linea su cui ti trovi.

Il problema è, tuttavia, che se si avesse la terza o la quarta riga abbinata/due /, si otterrebbe comunque lo stesso risultato. La soluzione di @ paxdiablo è più completa. Ma il mio è più Q D.