Saya mencoba grep untuk semua contoh Ui\.
tidak diikuti oleh Line
atau bahkan hanya hurufnyaL
Apa cara yang tepat untuk menulis regex untuk menemukan semua instance dari string tertentu TIDAK diikuti oleh string lain?
Menggunakan lookahead
grep "Ui\.(?!L)" *
bash: !L: event not found
grep "Ui\.(?!(Line))" *
nothing
regex
grep
regex-lookarounds
Lee Quarella
sumber
sumber
set +o histexpand
di Bash atauset +H
, YMMV.Jawaban:
Penampilan negatif, yang Anda cari, membutuhkan alat yang lebih kuat daripada standar
grep
. Anda membutuhkan grep yang mendukung PCRE.Jika Anda memiliki GNU
grep
, versi saat ini mendukung opsi-P
atau--perl-regexp
dan Anda dapat menggunakan regex yang Anda inginkan.Jika Anda tidak memiliki GNU (versi yang cukup baru)
grep
, pertimbangkan untuk mendapatkanack
.sumber
!
sebagai karakter khusus.-P
tidak didukung hasil pipa mencoba lagi untukgrep --invert-match
, ex:git log --diff-filter=D --summary | grep -E 'delete.*? src' | grep -E --invert-match 'xml'
. Pastikan untuk memberi suara positif pada jawaban @Vinicius Ottoni.Jawaban untuk sebagian dari masalah Anda ada di sini, dan ack akan berperilaku sama: Ack & pandangan negatif memberi kesalahan
Anda menggunakan tanda kutip ganda untuk grep, yang mengizinkan bash untuk "menafsirkan
!
sebagai perintah perluasan riwayat".Anda perlu membungkus pola Anda dalam TUNGGAL-KUTIPAN:
grep 'Ui\.(?!L)' *
Namun, lihat jawaban @ JonathanLeffler untuk mengatasi masalah dengan lookahead negatif secara standar
grep
!sumber
grep
dengan fungsionalitas standargrep
, di mana standarnyagrep
adalah POSIX. Apa yang Anda katakan juga benar - Saya menjalankan Bash dengan barbarisme C-shell dinonaktifkan (karena jika saya menginginkan shell C, saya akan menggunakan satu, tetapi saya tidak menginginkannya), jadi!
hal - hal tersebut tidak memengaruhi saya - tetapi untuk mendapatkan pandangan negatif, Anda perlu non-standargrep
.Anda mungkin tidak dapat melakukan lookahead negatif standar menggunakan grep, tetapi biasanya Anda bisa mendapatkan perilaku yang setara menggunakan tombol "invers" '-v'. Menggunakannya, Anda dapat membuat regex untuk melengkapi apa yang ingin Anda cocokkan, lalu menyalurkannya melalui 2 grep.
Untuk ekspresi reguler yang dimaksud, Anda dapat melakukan sesuatu seperti
sumber
Jika Anda perlu menggunakan implementasi regex yang tidak mendukung lookahead negatif dan Anda tidak keberatan mencocokkan karakter ekstra *, Anda dapat menggunakan kelas karakter yang dinegasikan
[^L]
, pergantian|
, dan akhir jangkar string$
.Dalam kasus Anda
grep 'Ui\.\([^L]\|$\)' *
melakukan pekerjaan itu.Ui\.
cocok dengan string yang Anda minati\([^L]\|$\)
cocok dengan salah satu karakter selainL
atau cocok dengan akhir baris:[^L]
atau$
.Jika Anda ingin mengecualikan lebih dari satu karakter, maka Anda hanya perlu membuang lebih banyak pergantian dan negasi padanya. Untuk menemukan
a
tidak diikuti olehbc
:grep 'a\(\([^b]\|$\)\|\(b\([^c]\|$\)\)\)' *
Yang bisa (
a
diikuti dengan tidakb
atau diikuti oleh akhir baris:a
lalu[^b]
atau$
) atau (a
diikuti olehb
yang diikuti dengan tidakc
atau diikuti oleh akhir baris:a
lalub
, lalu[^c]
atau$
.Ekspresi semacam ini menjadi sangat sulit dan rentan kesalahan bahkan dengan string pendek. Anda dapat menulis sesuatu untuk menghasilkan ekspresi untuk Anda, tetapi mungkin akan lebih mudah menggunakan implementasi regex yang mendukung lookahead negatif.
* Jika implementasi Anda mendukung grup yang tidak menangkap, maka Anda dapat menghindari pengambilan karakter tambahan.
sumber
Jika grep Anda tidak mendukung -P atau --perl-regexp, dan Anda dapat menginstal grep yang mendukung PCRE, misalnya "pcregrep", maka grep tidak memerlukan opsi baris perintah seperti GNU grep untuk menerima reguler yang kompatibel dengan Perl ekspresi, Anda baru saja lari
Anda tidak memerlukan grup bersarang lain untuk "Line" seperti dalam contoh "Ui. (?! (Line))" - grup luar sudah cukup, seperti yang saya tunjukkan di atas.
Izinkan saya memberi Anda contoh lain untuk melihat pernyataan negatif: ketika Anda memiliki daftar baris, dikembalikan oleh "ipset", setiap baris menunjukkan jumlah paket di tengah baris, dan Anda tidak memerlukan baris dengan paket nol, Anda hanya Lari:
Jika Anda menyukai ekspresi reguler yang kompatibel dengan perl dan memiliki perl tetapi tidak memiliki pcregrep atau grep Anda tidak mendukung --perl-regexp, Anda dapat menggunakan skrip perl satu baris yang bekerja dengan cara yang sama seperti grep:
Perl menerima stdin dengan cara yang sama seperti grep, misalnya
sumber