Bagaimana cara melakukan pertandingan non-serakah di grep?

Jawaban:

276

Anda mencari pasangan yang tidak serakah (atau malas). Untuk mendapatkan kecocokan tidak serakah dalam ekspresi reguler, Anda perlu menggunakan pengubah ?setelah pengukur. Misalnya, Anda dapat mengubah .*ke .*?.

Secara default greptidak mendukung pengubah non-serakah, tetapi Anda dapat menggunakan grep -Psintaks Perl.

Mark Byers
sumber
3
eegg: dot all modifier juga dikenal sebagai multiline. Ini adalah pengubah yang mengubah "." mencocokkan perilaku untuk memasukkan baris baru (biasanya tidak). Tidak ada pengubah seperti itu di grep, tetapi ada di pcregrep .
A. Wilson
1
Koreksi: Dalam sebagian besar rasa regex yang mendukungnya, mode yang memungkinkan .untuk mencocokkan baris baru disebut DOTALL atau mode single-line ; Ruby adalah satu-satunya yang menyebutnya multiline . Dalam rasa lain, multiline adalah mode yang memungkinkan jangkar ( ^dan $) cocok dengan batas garis. Ruby tidak memiliki mode yang sama karena di Ruby mereka selalu bekerja seperti itu.
Alan Moore
5
-Padalah benar-benar baru pada saya, saya dengan senang hati telah pergi selama bertahun-tahun, dan hanya menggunakan -E... bertahun-tahun yang terbuang sia-sia! - Catatan untuk diri sendiri: Baca kembali halaman manual sebagai (bahkan lebih!) Hal biasa, Anda tidak pernah mencerna cukup banyak saklar dan opsi.
ocodo
29
Pada beberapa platform (seperti Mac OS X) greptidak mendukung -P, tetapi jika Anda menggunakan egrepAnda dapat menggunakan .*?pola untuk mencapai hasil yang sama. egrep -o 'start.*?end' text.html
SaltyNuts
4
Sebagai ekstensi untuk komentar @SaltyNuts, Mac OS X tidak mendukung -Ptetapi -Eakan memanggil egrepkarena itu disarankan .*?berfungsi dengan baik.
Fredrik Erlandsson
83

Sebenarnya .*?satu - satunya yang berfungsi di perl. Saya tidak yakin apa yang setara dengan grep diperpanjang sintaks regexp akan. Untungnya Anda dapat menggunakan sintaks perl dengan grep sehingga grep -Pakan bekerja tetapi grep -Eyang sama egreptidak akan bekerja (itu akan serakah).

Lihat juga: http://blog.vinceliu.com/2008/02/non-greedy-regular-expression-matching.html

John Smith
sumber
9
grep -Ptidak bekerja di GNU grep 2.9 - hanya mencobanya (tidak error, hanya diam-diam tidak menerapkan ?. Intertestly juga tidak kelas misalnya:env|grep '[^\=]*\='
roberto tomás
2
Tidak ada grep -Popsi atau pgrepperintah di Darwin / OS X 10.8 Mountain Lion, tetapi egrepberfungsi dengan baik.
Steve HHH
2
Ada pgrepperintah pada kotak OS X 10.9 saya, tetapi ini adalah program yang sama sekali berbeda yang tujuannya adalah untuk "mencari atau memberi sinyal proses dengan nama".
Desty
@ robertotomás Menanggapi komentar 6 tahun di sini, tapi .... Saya pikir ini juga dan kemudian menyadari bahwa saya mendapatkan beberapa pertandingan yang tidak serakah. Misalnya, pada terminal warna Anda dapat melihat `echo" bbbbb "| grep -P 'b. *? b'` mengembalikan 2 kecocokan.
zzxyz
12

Grep saya yang berfungsi setelah mencoba hal-hal di utas ini:

echo "hi how are you " | grep -shoP ".*? "

Pastikan Anda menambahkan spasi ke setiap baris Anda

(Punyaku adalah pencarian baris demi baris untuk meludahkan kata-kata)

Jonon
sumber
3
-shoPmnemonic yang bagus :)
Mariusz
echo "bbbbb" | grep -shoP 'b.*?b'adalah sedikit pengalaman belajar. Satu-satunya hal yang berhasil bagi saya dalam hal malas secara eksplisit juga.
zzxyz
12

grep

Untuk pertandingan non-serakah di grepAnda bisa menggunakan kelas karakter yang dinegasikan. Dengan kata lain, cobalah untuk menghindari wildcard.

Misalnya, untuk mengambil semua tautan ke file jpeg dari konten halaman, Anda akan menggunakan:

grep -o '"[^" ]\+.jpg"'

Untuk menangani beberapa saluran, pipa input xargsterlebih dahulu. Untuk kinerja, gunakan ripgrep.

kenorb
sumber
3

Jawaban singkatnya menggunakan ekspresi reguler berikutnya:

(?s)<car .*? model=BMW .*?>.*?</car>
  • (? s) - ini membuat kecocokan di seluruh multiline
  • . *? - cocok dengan karakter apa pun, beberapa kali dengan cara malas (kecocokan minimal)

Jawaban (sedikit) yang lebih rumit adalah:

(?s)<([a-z\-_0-9]+?) .*? model=BMW .*?>.*?</\1>

Ini memungkinkan untuk mencocokkan car1 dan car2 dalam teks berikut

<car1 ... model=BMW ...>
...
...
...
</car1>
<car2 ... model=BMW ...>
...
...
...
</car2>
  • (..) mewakili grup penangkap
  • \ 1 dalam konteks ini cocok dengan sametext sebagai yang paling baru dicocokkan dengan menangkap nomor grup 1
jmc
sumber
1

Maaf saya terlambat 9 tahun, tapi ini mungkin berhasil untuk pemirsa pada tahun 2020.

Jadi misalkan Anda memiliki garis seperti "Hello my name is Jello". Sekarang Anda ingin menemukan kata-kata yang dimulai dengan 'H'dan diakhiri dengan 'o', dengan sejumlah karakter di antaranya. Dan kami tidak ingin kalimat, kami hanya ingin kata-kata. Jadi untuk itu kita bisa menggunakan ekspresi:

grep "H[^ ]*o" file

Ini akan mengembalikan semua kata. Cara kerjanya adalah: Ini akan memungkinkan semua karakter alih-alih karakter spasi di antaranya, dengan cara ini kita dapat menghindari beberapa kata di baris yang sama.

Sekarang Anda dapat mengganti karakter spasi dengan karakter lain yang Anda inginkan. Misalkan baris awal tadi "Hello-my-name-is-Jello", maka Anda bisa mendapatkan kata-kata menggunakan ekspresi:

grep "H[^-]*o" file
mr.1n5an_e
sumber
0

Saya tahu bahwa ini sedikit posting yang sudah mati, tetapi saya perhatikan bahwa ini berhasil. Itu menghapus pembersihan dan pembersihan dari output saya.

> grep -v -e 'clean\-\?up'
> grep --version grep (GNU grep) 2.20
pengguna200850
sumber