Hapus baris yang berisi string tertentu dan baris berikut

71

Saya menggunakan ini

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

untuk menghapus baris yang berisi string bardalam file.

Namun saya ingin menghapus garis-garis dan garis langsung setelahnya . Lebih disukai di sed, awkatau alat lain yang tersedia di MinGW32.

Ini semacam kebalikan dari apa yang aku bisa di grepdengan -Adan -Buntuk mencetak garis pencocokan serta jalur sebelum / setelah baris cocok.

Apakah ada cara mudah untuk mencapainya?

jakub.g
sumber
2
Sekadar informasi: Saya sedang menganalisis log di mana entri adalah dua-baris. Jadi saya ingin menemukan entri yang cocok dengan pola dan menghapusnya serta baris berikutnya. Karenanya saya tidak perlu menangani garis pertandingan berurutan, tetapi tetap terima kasih atas kelengkapan jawaban Anda!
jakub.g

Jawaban:

75

Jika Anda memiliki GNU sed (Linux atau Cygwin yang tidak tertanam):

sed '/bar/,+1 d'

Jika Anda memiliki bardua baris berturut-turut, ini akan menghapus baris kedua tanpa menganalisisnya. Misalnya, jika Anda memiliki file 3-line bar/ bar/ foo, yang foogaris akan tinggal.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
1
+1 untuk panjang :) Dalam contoh khusus saya, saya tidak memiliki berurutan barsehingga yang ini sangat mudah diingat.
jakub.g
11
sed '/bar/d'jika Anda hanya ingin "Hapus baris yang berisi string tertentu" dan bukan yang berikutnya.
AJP
Jika saya ingin menghapus semua baris setelah matematika itu?
Pandya
1
@ Pandya Itu berbeda. Anda dapat menggunakan misalnyased '/math/q'
Gilles 'SO- stop being evil'
1
@AK Jika Anda hanya ingin menghapus baris yang cocok, itu bahkan lebih sederhana:sed '/bar/d'
Gilles 'SO- stop being evil'
16

Jika bardapat terjadi pada baris yang berurutan, Anda dapat melakukan:

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

yang dapat diadaptasi untuk menghapus lebih dari 2 baris dengan mengubah 2 di atas dengan jumlah baris yang akan dihapus termasuk yang cocok.

Jika tidak, itu mudah dilakukan seddengan solusi @MichaelRollins atau:

sed '/bar/,/^/d' < infile > outfile
Stéphane Chazelas
sumber
Kelebihan lainnya dalam solusi AWK adalah bahwa saya dapat mengganti /bar/dengan /bar|baz|whatever/. Dalam sedsintaks itu sepertinya tidak berfungsi.
jakub.g
@ jakub.g, Saya memiliki GNU sed (v4.4 sekarang). Tidak yakin mengenai yang lain. Yang saya tahu adalah bahwa ia menggunakan sintaks ekspresi reguler "dasar" secara default, inilah mengapa contoh Anda tidak berfungsi. Untuk mencapai apa yang Anda inginkan, Anda bisa meletakkan garis miring terbalik di depan setiap garis vertikal atau Anda dapat meminta seduntuk menggunakan ekspresi reguler "extended". Informasi lebih lanjut di sini: gnu.org/software/sed/manual/html_node/… . Harap dicatat bahwa ini juga berlaku untuk grep. Berikut contoh kerja saya sendiri: echo $'0a\n1b\n2c' | sed '/0a\|1b/d'.
Victor Yarema
12

Saya tidak lancar dalam sed, tetapi mudah untuk melakukannya dalam awk:

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

Script awk berbunyi: untuk baris yang berisi bar, dapatkan baris berikutnya (getline), lalu lewati semua pemrosesan selanjutnya (selanjutnya). Pola 1 di ujung mencetak garis yang tersisa.

Memperbarui

Seperti yang ditunjukkan dalam komentar, solusi di atas tidak bekerja secara berurutan bar. Berikut adalah solusi yang telah direvisi, yang mempertimbangkannya:

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

Kami sekarang terus membaca untuk melewati semua / bar / baris.

Hai Vu
sumber
1
Untuk mereplikasi grep -A100%, Anda juga perlu menangani sejumlah bargaris berturut-turut dengan benar (dengan menghapus seluruh blok dan 1 baris setelahnya).
jw013
7

Anda akan ingin memanfaatkan kemampuan skrip sed untuk mencapai ini.

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

Contoh data:

$ cat sample1.txt 
foo
bar
biz
baz
buz

Perintah "N" menambahkan baris input berikutnya ke dalam ruang pola. Ini dikombinasikan dengan garis dari pencocokan pola (/ bar /) akan menjadi garis yang ingin Anda hapus. Anda kemudian dapat menghapus secara normal dengan perintah "d".

Michael Rollins
sumber
Bagaimana cara saya mengetik baris baru di konsol? Atau ini hanya skrip?
jakub.g
@ jakub.g: dengan GNU sed:sed -e '/bar/{N;d}' sample1.txt
Cyrus
2

Jika ada garis segera setelah pertandingan harus dihapus maka sedprogram Anda harus mempertimbangkan pertandingan berturut-turut. Dengan kata lain, jika Anda menghapus garis mengikuti pertandingan yang juga cocok, maka mungkin Anda harus menghapus garis yang mengikuti itu juga.

Ini diterapkan cukup sederhana - tetapi Anda harus melihat ke belakang sedikit.

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

Ini bekerja dengan menukar ruang pegang dan pola untuk setiap baris yang dibaca - sehingga baris terakhir dapat dibandingkan dengan saat ini setiap kali. Jadi ketika sedmembaca sebuah baris, ia bertukar konten buffer-nya - dan baris sebelumnya kemudian isi dari buffer editnya, sedangkan baris saat ini diletakkan di ruang penyimpanan.

Jadi, sedperiksa baris sebelumnya untuk kecocokan match, dan jika !tidak ditemukan dua ekspresi dalam {fungsi }dijalankan. sedakan get pegangan ruang dengan Timpa ruang pola - yang berarti baris saat kemudian di kedua ditahan dan pola ruang - dan kemudian akan //memeriksa untuk pertandingan ke ekspresi reguler yang paling baru-baru ini disusun - match- dan jika itu tidak matchitu adalah printed.

Ini berarti suatu garis hanya dicetak jika tidak dan garis sebelumnya tidak . Ini juga membatalkan pertukaran yang tidak perlu untuk urutan es.match matchmatch

Jika Anda menginginkan versi yang dapat menjatuhkan jumlah baris sewenang-wenang yang terjadi setelahnya, matchitu akan membutuhkan sedikit lebih banyak pekerjaan:

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

... ganti 5 dengan jumlah garis (termasuk garis yang cocok) yang ingin Anda hapus ...


1
2
3
4
12
13
14
21
mikeserv
sumber