Grep regex TIDAK mengandung string

182

Saya melewati daftar pola regex grepuntuk memeriksa file syslog. Mereka biasanya cocok dengan alamat IP dan entri log;

grep "1\.2\.3\.4.*Has exploded" syslog.log

Itu hanya daftar pola seperti "1\.2\.3\.4.*Has exploded"bagian yang saya lewati, dalam satu lingkaran, jadi saya tidak bisa melewatkan "-v" misalnya.

Saya bingung mencoba melakukan kebalikan dari yang di atas, garis TIDAK cocok dengan alamat IP dan kesalahan tertentu jadi "! 1.2.3.4. * Telah meledak" akan cocok dengan baris syslog untuk apa pun selain 1.2.3.4 mengatakan kepada saya itu telah meledak . Saya harus bisa memasukkan IP agar TIDAK cocok.

Saya telah melihat berbagai posting serupa di StackOverflor namun mereka menggunakan pola regex yang sepertinya tidak bisa saya kerjakan grep. Adakah yang bisa memberikan contoh kerja untuk greptolong?

PEMBARUAN: Ini terjadi dalam skrip seperti ini;

patterns[1]="1\.2\.3\.4.*Has exploded"
patterns[2]="5\.6\.7\.8.*Has died"
patterns[3]="\!9\.10\.11\.12.*Has exploded"

for i in {1..3}
do
 grep "${patterns[$i]}" logfile.log
done
jwbensley
sumber
Apakah maksud Anda terkadang Anda ingin mencocokkan suatu pola, tetapi di waktu lain ingin mencocokkan semuanya kecuali pola tertentu? (Ini sepertinya persyaratan aneh, tapi apa pun). Dalam hal itu, mengapa Anda tidak mengulangi dua daftar pola yang berbeda?
beerbajay
Yah saya tidak begitu tahu tentang regex; Saya tidak ingin menerima "Telah Meledak" karena saya tidak ingin tahu ini tentang setiap perangkat logging, jadi bisakah saya entah bagaimana menerima "Telah Meledak" dan! 9.10.11.12 dalam satu pernyataan?
jwbensley
Jika Anda benar-benar harus melakukannya dalam satu pernyataan, pandangan negatif adalah jalan yang harus ditempuh, seperti yang disarankan Neil. Lihat komentar saya di sana.
beerbajay
Gunakan pencocokan regex gaya PCRE, dan pernyataan lookahead negatif, sesuai jawaban @Neil: patterns[3]="\!9\.10\.11\.12.*Has exploded"perubahan patterns[3]="(?<!9\.10\.11\.12).*Has exploded"dan grep "${patterns[$i]}" logfile.logperubahan pada grep -P "${patterns[$i]}" logfile.logPCRE mengasumsikan lebih banyak karakter meta secara default, sehingga beberapa pelarian mungkin perlu dihilangkan dari ekspresi pencocokan lainnya.
Codex24

Jawaban:

342

grepcocok, grep -vapakah kebalikannya. Jika Anda perlu "mencocokkan A tetapi bukan B" Anda biasanya menggunakan pipa:

grep "${PATT}" file | grep -v "${NOTPATT}"
Beerbajay
sumber
Ini masuk ke tengah-tengah loop seperti yang saya sebutkan dan saya hanya melewati POLA untuk grep jadi saya tidak bisa menggunakan "-v" seperti yang saya sebutkan. Saya hanya mengulang daftar POLA dan memberikan grep.
jwbensley
1
Anda memang bisa menggunakan -vdan Anda bisa menggunakannya dalam satu lingkaran. Mungkin Anda perlu lebih spesifik tentang keterbatasan Anda, atau mungkin Anda memiliki kesalahpahaman tentang bagaimana skrip Anda seharusnya bekerja. Coba posting beberapa kode.
beerbajay
Terima kasih beerbajay, saya telah menambahkan kode yang dipotong ke pos asli untuk memberikan beberapa konteks. Apakah Anda mengerti maksud saya sekarang?
jwbensley
Jawaban ini tidak sepenuhnya benar tetapi Anda cukup banyak menulis beerbajay, saya perlu memikirkan kembali loop dan digunakan -v pada akhirnya. Terima kasih atas penunjuknya;)
jwbensley
1
Tetapi bagaimana jika A terdiri dari B? Dengan kata lain, bagaimana jika saya ingin mencocokkan garis tanpa A dan garis dengan AB? Sebuah pipa tidak akan berfungsi.
pawamoy
15
(?<!1\.2\.3\.4).*Has exploded

Anda perlu menjalankan ini dengan -P untuk memiliki tampilan negatif di belakang (Perl regular expression), jadi perintahnya adalah:

grep -P '(?<!1\.2\.3\.4).*Has exploded' test.log

Coba ini. Ini menggunakan tampilan negatif di belakang untuk mengabaikan garis jika didahului oleh 1.2.3.4. Semoga itu bisa membantu!

Neil
sumber
1
Saya cukup yakin itu greptidak mendukung lookaround. Kecuali jika Anda menggunakan Gnu grepdan menggunakan --Pparameter untuk membuatnya menggunakan mesin PCRE.
Tim Pietzcker
Tidak, grep tidak mendukung Regex jenis ini; $ grep -P (? <\! 1 \ .2 \ .3 \ .4) test.log -bash: kesalahan sintaksis dekat token yang tidak terduga `('
jwbensley
Anda perlu mengutip regex jika berisi karakter yang akan ditafsirkan oleh shell.
beerbajay
mengoreksi dengan benar: grep -P '(?<!1\.2\.3\.4) Has exploded' test.logPerhatikan bahwa tampilan di belakang hanya berfungsi pada karakter segera sebelum bagian yang cocok dari ekspresi, jadi jika ada hal-hal lain antara alamat dan pesan, misalnya 1.2.3.4 FOO Has exploded, ini tidak akan berfungsi.
beerbajay
@TimPietzcker, sangat jeli. Saya akan menambahkan itu ke pertanyaan. Juga, harap dicatat bahwa ada tampilan .*negatif di belakang karena contohnya juga ada, saya bayangkan mungkin ada teks lain di antaranya.
Neil
2
patterns[1]="1\.2\.3\.4.*Has exploded"
patterns[2]="5\.6\.7\.8.*Has died"
patterns[3]="\!9\.10\.11\.12.*Has exploded"

for i in {1..3}
 do
grep "${patterns[$i]}" logfile.log
done

harus sama dengan

egrep "(1\.2\.3\.4.*Has exploded|5\.6\.7\.8.*Has died)" logfile.log | egrep -v "9\.10\.11\.12.*Has exploded"    
Krecker
sumber