Bagaimana cara grep -v dan juga mengecualikan baris berikutnya setelah pertandingan?


14

Bagaimana cara memfilter 2 baris untuk setiap baris yang cocok dengan grep regex?
ini adalah tes minimal saya:

SomeTestAAAA
EndTest
SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestAABC
EndTest
SomeTestACDF
EndTest

Dan jelas saya mencoba misalnya grep -vA 1 SomeTestAAyang tidak berhasil.

output yang diinginkan adalah:

SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest

grep -v 'SomeTextAA' | unik?
DarkHeart

Jawaban:


14

Anda dapat menggunakan grepdengan -P(PCRE):

grep -P -A 1 'SomeTest(?!AA)' file.txt

(?!AA)adalah pola lookahead negatif lebar nol memastikan bahwa tidak ada AAsetelah SomeTest.

Uji :

$ grep -P -A 1 'SomeTest(?!AA)' file.txt 
SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest

apa karakter pelarian untuk titik-titik? seperti Some.Test.AA?
Behrooz

1
@Behrooz Escape dots by \.so grep -P -A 1 'SomeTest\.(?!AA)' file.txtorgrep -P -A 1 'SomeTest(?!\.AA)' file.txt
heemayl

Ini berfungsi dalam kasus khusus ini karena dalam baris sampel SomeTest*\nEndTestOPs berpasangan sehingga Anda benar-benar melakukan grepping semua baris yang cocok SomeTest*tetapi tidak SomeTestAA+ satu baris konteks setelah pertandingan. Tambahkan beberapa baris lagi ke input (mis. Tambahkan baris foobarsetelah setiap EndTestbaris) lalu coba lagi.
don_crissti

1
@don_crissti itu benar, saya sudah mengatasinya.
Behrooz

@Behrooz - peduli untuk berbagi dengan kami bagaimana Anda mengatasi hal itu dan mungkin menjawab komentar saya di bawah pertanyaan Anda?
don_crissti

4

Inilah sedsolusi ( -ntanpa percetakan otomatis) yang berfungsi dengan input sewenang-wenang:

sed -n '/SomeTestAA/!p          # if line doesn't match, print it
: m                             # label m
//{                             # if line matches
$!{                             # and if it's not the last line
n                               # empty pattern space and read in the next line
b m                             # branch to label m (so n is repeated until a
}                               # line that's read in no longer matches) but
}                               # nothing is printed
' infile

demikian dengan input like

SomeTestAAXX
SomeTestAAYY
+ one line
SomeTestONE
Message body
EndTest
########
SomeTestTWO
something here
EndTest
SomeTestAABC
+ another line
SomeTestTHREE
EndTest
SomeTestAA
+ yet another line

berlari

sed -n -e '/SomeTestAA/!p;: m' -e '//{' -e '$!{' -e 'n;b m' -e '}' -e'}' infile

output

SomeTestONE
Message body
EndTest
########
SomeTestTWO
something here
EndTest
SomeTestTHREE
EndTest

yaitu, ia menghapus persis garis yang grep -A1 SomeTestAA infileakan memilih:

SomeTestAAXX
SomeTestAAYY
+ one line
--
SomeTestAABC
+ another line
--
SomeTestAA
+ yet another line

Menarik. Saya tidak menyadari bahwa //cocok /SomeTestAA/. Saya pikir, dalam hal ini, itu akan cocok dengan ekspresi menegasikan: /SomeTestAA/!. (+1)
Peter.O

@ Peter.O - terima kasih! Tidak, sesuai spesifikasinya, RE kosong harus selalu cocok dengan RE terakhir yang digunakan dalam perintah terakhir; yang !bukan bagian dari RE , itu adalah sedhal.
don_crissti

3

Anda mungkin lebih beruntung dengan sesuatu yang melihat wilayah multi-baris sebagai rekaman tunggal. Ada sgrepyang belum banyak saya gunakan.

Ada juga awk, di mana Anda dapat mengatur pemisah catatan input, dan pemisah catatan keluaran, apa pun yang Anda suka.

pat="^SomeTestAA"
awk  'BEGIN{ RS=ORS="\nEndTest\n"} !/'"$pat/" foo

Sebagian besar program awk adalah tanda kutip tunggal, tetapi saya mengubah menjadi tanda kutip ganda di akhir sehingga $patvariabel shell dapat diperluas.


awk -vpat="^SomeTestAA" -vRS="\nEndTest\n" 'BEGIN{ ORS=RS } $0 !~ pat' file
Peter.O

3

Salah satu pilihan adalah untuk penggunaan pErl compatible regular eXpression grep:

pcregrep -Mv 'SomeTestAA.*\n' file

Opsi ini -Mmemungkinkan pola untuk mencocokkan lebih dari satu baris.


1
@don_crissti Kedua baris akan dihapus. Spesifikasi OP tidak mencakup kasus ini.
jimmij

Sudah cukup jelas sampel & pertanyaan OP tidak mencakup kasus-kasus seperti itu, saya hanya ingin tahu bagaimana ini bekerja (saya tidak terbiasa dengan pcre) karena dengan jumlah ganjil dari baris berturut-turut yang cocok, ini berfungsi (ini menghilangkan baris konteks juga) dan dengan jumlah garis berturut-turut yang cocok, itu gagal (tidak menghapus baris konteks setelah).
don_crissti

Mengingat (GNU) grepsudah mendukung PCRE (melalui -Popsi), apa keuntungan menggunakan pcregrep?
arielf

@diri grepsendiri tidak mendukung -Mopsi.
jimmij

1

Menggunakan standar sed:

$ sed '/SomeTestAA/{ N; d; }' file
SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest

The sedScript mem-parsing file baris masukan demi baris, dan ketika garis sesuai dengan pola SomeTestAA, dua sedperintah editing Ndan ddieksekusi. The Nperintah menambahkan baris berikutnya dari input ke ruang pola (buffer yang seddapat mengedit), dan dmenghapus ruang pola dan mulai siklus berikutnya.


1

Sudah mencoba dengan perintah sed di bawah ini dan itu bekerja dengan baik

perintah

sed  '/SomeTestAA/,+1d' filename

keluaran

SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest

0

Anda dapat menggunakan GNU sed's dperintah untuk menghapus garis, dan awalan dengan /pat/,+Nuntuk memilih baris yang cocok dengan pola dan selanjutnya N baris. Dalam kasus Anda, N = 1 karena Anda hanya ingin menghapus satu baris berikutnya setelah satu baris yang cocok:

sed -e '/SomeTestAAAA/,+1d'
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.