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/
. Insed
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 agrep
. 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 dibar
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