Rimuovi la riga contenente una determinata stringa e la riga seguente

Io la uso

cat foo.txt | sed "/bar/d"

per rimuovere le righe contenenti la stringa bar nel file.

Vorrei tuttavia rimuovere quelle righe e la riga direttamente dopo di esso . Preferibilmente in sed, awk o in un altro strumento disponibile in MinGW32.

È “una specie di inversione di ciò che posso ottenere in grep con -A e -B per stampare anche le righe corrispondenti come righe prima / dopo la riga corrispondente.

Esiste un modo semplice per ottenerlo?

Commenti

  • Solo per informazioni: ‘ m analizzo i log in cui le voci sono a due righe. Quindi voglio trovare una voce che corrisponda al modello e rimuoverla così come la riga successiva. Quindi ‘ non ho bisogno di gestire linee di corrispondenza consecutive, ma grazie comunque per la completezza delle tue risposte!

Risposta

Se hai GNU sed (quindi Linux o Cygwin non incorporato):

sed "/bar/,+1 d" 

Se tu avere bar su due righe consecutive, questo eliminerà la seconda riga senza analizzarla. Ad esempio, se hai un file di 3 righe bar / bar / foo, la riga foo rimarrà.

Commenti

  • +1 per la lunghezza 🙂 Nel mio particolare esempio Non ‘ ho bar consecutivi, quindi questo è facilissimo da ricordare.
  • sed '/bar/d' se desideri ” Rimuovi la riga contenente una determinata stringa ” e non il prossimo.
  • Se voglio rimuovere tutte le righe dopo la matematica, allora?
  • @Pandya Questo ‘ è diverso. Puoi usare ad es. sed '/math/q'
  • @ A.K. Se desideri eliminare la riga corrispondente, ‘ è ancora più semplice: sed '/bar/d'

Risposta

Se bar può essere visualizzato su righe consecutive, potresti:

awk "/bar/{n=2}; n {n--; next}; 1" < infile > outfile 

che può essere adattato per eliminare più di 2 righe modificando le 2 precedenti con il numero di righe da eliminare inclusa quella corrispondente.

In caso contrario, “è facilmente eseguibile in sed con la soluzione @MichaelRollins” o:

sed "/bar/,/^/d" < infile > outfile 

Commenti

  • Laltro vantaggio nella soluzione AWK è che posso sostituire /bar/ con /bar|baz|whatever/. In sed quella sintassi ‘ non sembra funzionare.
  • @ jakub.g, ho GNU sed ( v4.4 ora). Non sono sicuro degli altri. Quello che so è che utilizza la sintassi delle espressioni regolari ” basic ” per impostazione predefinita, ecco perché il tuo esempio non ‘ t funziona. Per ottenere ciò che desideri, puoi inserire una barra rovesciata davanti a ciascuna linea verticale oppure chiedere a sed di utilizzare ” esteso ” espressioni regolari. Ulteriori informazioni qui: gnu.org/software/sed/manual/html_node/… . Tieni presente che questo è applicabile anche a grep. Ecco ‘ il mio esempio funzionante: echo $'0a\n1b\n2c' | sed '/0a\|1b/d'.

Risposta

Non parlo fluentemente sed, ma è facile farlo in awk:

awk "/bar/{getline;next} 1" foo.txt 

Il Lo script awk legge: per una riga contenente bar, ottieni la riga successiva (getline), quindi salta tutte le elaborazioni successive (next). Il modello 1 alla fine stampa le righe rimanenti.

Aggiorna

Come sottolineato nel commento, la soluzione precedente non ha funzionato con bar. Ecco una soluzione rivista, che la prende in considerazione:

awk "/bar/ {while (/bar/ && getline>0) ; next} 1" foo.txt 

Ora continuiamo a leggere per saltare tutte le / bar / righe.

Commenti

  • Per replicare grep -A al 100%, devi anche gestire un numero qualsiasi di bar righe correttamente (rimuovendo lintero blocco e 1 riga dopo).

Risposta

Ti consigliamo di utilizzare le capacità di scripting di sed per eseguire questa operazione.

$ sed -e "/bar/ { $!N d }" sample1.txt 

Dati di esempio:

$ cat sample1.txt foo bar biz baz buz 

Il comando “N” aggiunge la successiva riga di input nello spazio del pattern. Questo combinato con la riga del pattern match (/ bar /) saranno le righe che desideri eliminare. Puoi quindi cancellare normalmente con il comando “d”.

Commenti

  • Come si digita una nuova riga nella console? Oppure è solo script?
  • @ jakub.g: con GNU sed: sed -e '/bar/{N;d}' sample1.txt

Risposta

Se una qualsiasi riga immediatamente successiva a una corrispondenza deve essere rimossa, il programma sed dovrà considerare corrispondenze consecutive. In altre parole, se rimuovi una riga che segue una corrispondenza che corrisponde anche a quella, probabilmente dovresti rimuovere anche la riga che segue.

È implementata abbastanza semplicemente, ma devi guardare un po dietro .

printf %s\\n 0 match 2 match match \ 5 6 match match match \ 10 11 12 match 14 15 | sed -ne"x;/match/!{g;//!p;}" 

 0 6 11 12 15  

Funziona scambiando hold e spazi pattern per ogni riga letta, così lultima riga può essere confrontata ogni volta con quella corrente. Quindi, quando sed legge una riga, scambia il contenuto dei suoi buffer – e la riga precedente è quindi il contenuto del suo buffer di modifica, mentre la riga corrente viene messa in attesa.

Quindi sed controlla la riga precedente per una corrispondenza con match e se il suo ! non ha trovato le due espressioni nella { funzione } vengono eseguite. sed g imposta lo spazio di blocco sovrascrivendo lo spazio del pattern, il che significa che la riga corrente si trova sia negli spazi di blocco che in quelli del pattern – e quindi // verificherà la corrispondenza con la sua espressione regolare compilata più di recente – match – e se esso non match è p stampato.

Ciò significa che una riga viene stampata solo se non match e la riga immediatamente precedente non match . Inoltre rinuncia a qualsiasi scambio non necessario per sequenze di match es.

Se si desidera una versione che potrebbe eliminare un numero arbitrario di righe che si verifica dopo un match richiederebbe un po più di lavoro:

printf %s\\n 1 2 3 4 match \ match match 8 \ 9 10 11 12 13 \ 14 match match \ 17 18 19 20 21 | sed -net -e"/match/{h;n;//h;//!H;G;s/\n/&/5;D;}" -ep 

. ..sostituisci il 5 con il numero di righe (inclusa la riga corrispondente) che desideri rimuovere …


1 2 3 4 12 13 14 21 

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *