Rimuovere la riga contenente una determinata stringa e la riga seguente


71

Io lo uso

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

per rimuovere le righe contenenti la stringa barnel file.

Vorrei tuttavia rimuovere quelle linee e la linea subito dopo . Preferibilmente in sed, awko altro strumento che è disponibile in mingw32.

E 'una sorta di inversione di quello che posso ottenere in grepcon -Ae -Bper la stampa le linee corrispondenti e le linee prima / dopo la riga corrispondente.

C'è un modo semplice per raggiungerlo?


2
Solo per informazione: sto analizzando i log in cui le voci sono a due righe. Quindi voglio trovare una voce corrispondente al modello e rimuoverla così come la riga successiva. Quindi non ho bisogno di gestire le linee di corrispondenza consecutive, ma grazie comunque per la completezza delle tue risposte!
jakub.g

Risposte:


75

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

sed '/bar/,+1 d'

Se hai bardue righe consecutive, questa eliminerà la seconda riga senza analizzarla. Ad esempio, se si dispone di un file a 3 righe bar/ bar/ foo, la fooriga rimarrà.


1
+1 per la lunghezza :) Nel mio esempio particolare non ho bars consecutivi , quindi questo è super facile da ricordare.
jakub.g

11
sed '/bar/d'se desideri semplicemente "Rimuovi riga contenente una determinata stringa" e non la successiva.
AJP

Se voglio rimuovere tutte le righe dopo la matematica, allora?
Pandya,

1
@Pandya È diverso. Puoi usare ad esempiosed '/math/q'
Gilles 'SO- smetti di essere malvagio'

1
@AK Se vuoi solo eliminare la riga corrispondente, è ancora più semplice:sed '/bar/d'
Gilles 'SO- smetti di essere malvagio' il

16

Se barpuò verificarsi su righe consecutive, è possibile eseguire:

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 eseguibilesed con la soluzione di @MichaelRollins o:

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

Un altro vantaggio nella soluzione AWK è che posso sostituire /bar/con /bar|baz|whatever/. In sedquella sintassi non sembra funzionare.
jakub.g

@ jakub.g, ho GNU sed (v4.4 ora). Non sono sicuro degli altri. Quello che so è che usa la sintassi delle espressioni regolari "base" per impostazione predefinita, per questo il tuo esempio non ha funzionato. Per ottenere ciò che desideri puoi mettere una barra rovesciata davanti a ciascuna linea verticale oppure puoi chiedere seddi usare espressioni regolari "estese". Maggiori informazioni qui: gnu.org/software/sed/manual/html_node/… . Si prega di notare che questo è applicabile grepanche a. Ecco il mio esempio di lavoro: echo $'0a\n1b\n2c' | sed '/0a\|1b/d'.
Victor Yarema,

12

Non sono fluente in sed, ma è facile farlo in awk:

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

Lo script awk recita: per una riga contenente la barra, ottenere la riga successiva (getline), quindi saltare tutta l'elaborazione successiva (successiva). Il motivo 1 alla fine stampa le linee rimanenti.

Aggiornare

Come sottolineato nel commento, la soluzione di cui sopra non ha funzionato con consecutivi 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 / linee.


1
Per replicare al grep -A100%, devi anche gestire barcorrettamente un numero qualsiasi di righe consecutive (rimuovendo l'intero blocco e 1 riga dopo).
jw013

7

Ti consigliamo di utilizzare le funzionalità di scripting di sed per raggiungere questo obiettivo.

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

Dati di esempio:

$ cat sample1.txt 
foo
bar
biz
baz
buz

Il comando "N" aggiunge la riga successiva di input nello spazio modello. Questo combinato con la linea della corrispondenza del modello (/ bar /) saranno le linee che desideri eliminare. È quindi possibile eliminare normalmente con il comando "d".


Come si digita una newline in console? O questo è solo script?
jakub.g

@ jakub.g: con GNU sed:sed -e '/bar/{N;d}' sample1.txt
Cyrus,

2

Se una riga immediatamente successiva a una partita deve essere rimossa, il tuo sedprogramma dovrà considerare le partite consecutive. In altre parole, se rimuovi una riga dopo una corrispondenza che corrisponde anche, probabilmente dovresti rimuovere anche la riga successiva.

È implementato in modo abbastanza semplice, ma devi guardare un po 'indietro.

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 gli spazi hold e pattern per ogni riga letta, in modo che l'ultima riga possa essere confrontata con la corrente ogni volta. Quindi quando sedlegge 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 sedcontrolla la riga precedente per una corrispondenza matche, se !non viene trovata {, }vengono eseguite le due espressioni nella funzione . sedsarà get lo spazio stiva sovrascrivendo spazio pattern - che significa che la linea corrente è quindi in entrambi gli spazi di attesa e pattern - e poi sarà //controllare una corrispondenza per l'espressione regolare più recente compilato - match- e se esso non fa matchche è psfilato.

Ciò significa che una riga viene stampata solo in caso contrario e la riga immediatamente precedente no . Rinuncia anche a qualsiasi scambio non necessario per sequenze di es.match matchmatch

Se si desidera una versione che potrebbe eliminare un numero arbitrario di righe che si verificano dopo una match, sarebbe necessario 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 linee (inclusa la linea abbinata) che desideri rimuovere ...


1
2
3
4
12
13
14
21
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.