Menggunakan tanda bintang di grep

90

Saya mencoba mencari substring "abc" di file tertentu di linux / bash

Jadi saya melakukan:

grep '*abc*' myFile

Itu tidak mengembalikan apa-apa.

Tetapi jika saya melakukannya:

grep 'abc' myFile

Ini mengembalikan pertandingan dengan benar.

Sekarang, ini bukan masalah bagi saya. Tetapi bagaimana jika saya ingin grep untuk string yang lebih kompleks, katakanlah

*abc * def *

Bagaimana cara melakukannya dengan grep?

Saobi
sumber
3
grep sendiri tidak mendukung karakter pengganti di sebagian besar platform. Anda harus menggunakan egrep untuk menggunakan wildcard. Kerang memiliki sintaks yang berbeda. "*" di shell adalah <any string>. Dalam egrep itu adalah operator yang mengatakan "0 ke banyak entitas sebelumnya". Dalam grep, itu hanya karakter biasa.
PanCrit
@ PanCrit: *berarti hal yang sama dalam grep dan egrep: ini adalah pembilang yang berarti nol atau lebih dari atom sebelumnya. Itu adalah konsep yang sama sekali berbeda dari karakter pengganti yang digunakan oleh shell.
Alan Moore

Jawaban:

124

Tanda bintang hanyalah operator pengulangan , tetapi Anda perlu memberi tahu apa yang Anda ulangi. /*abc*/cocok dengan string yang berisi ab dan nol atau lebih c (karena * kedua ada di c; yang pertama tidak ada artinya karena tidak ada yang diulangi). Jika Anda ingin mencocokkan apa pun, Anda perlu mengatakan .*- titik berarti karakter apa pun ( dalam pedoman tertentu ). Kalau mau cocok aja abc, tinggal bilang aja grep 'abc' myFile. Untuk kecocokan yang lebih kompleks, Anda perlu menggunakan .*- grep 'abc.*def' myFileakan mencocokkan string yang berisi abc diikuti def dengan sesuatu opsional di antaranya.

Pembaruan berdasarkan komentar:

*dalam ekspresi reguler tidak persis sama dengan * di konsol. Di konsol, * adalah bagian dari a konstruksi glob , dan hanya bertindak sebagai karakter pengganti (misalnya ls *.logakan mencantumkan semua file yang diakhiri dengan .log). Namun, dalam ekspresi reguler, * adalah pengubah, artinya ini hanya berlaku untuk karakter atau grup yang mendahuluinya. Jika Anda ingin * dalam ekspresi reguler berfungsi sebagai karakter pengganti, Anda perlu menggunakan .*seperti yang disebutkan sebelumnya - titik adalah karakter karakter pengganti, dan bintang, saat mengubah titik, berarti menemukan satu atau beberapa titik; yaitu. temukan satu atau lebih karakter apa pun.

Daniel Vandersluis
sumber
1
Saya pikir penanya bingung tentang perbedaan antara kartu bebas shell dan ekspresi reguler. Saya juga menduga bahwa ekspresi yang lebih rumit adalah: grep 'abc. * Def' (setidaknya ada satu spasi - mungkin dua seperti yang saya tulis).
Jonathan Leffler
1
Sebenarnya, penanya sepertinya tidak mengerti bahwa 'abc' tidak sama dengan '^ abc $' :-D
Massa
1
Ya, saya bingung antara ekspresi reguler dan glob. Saya menggunakan * tanpa titik yang berarti mencocokkan apa pun di shell.
Saobi
1
grep *berarti "0 atau lebih", dan grep secara default adalah serakah. Perhatikan bahwa dalam grep dasar ekspresi reguler yang metakarakter ?, +, {, |, (, dan )kehilangan makna khusus mereka. Info lebih lanjut: grep regexps
KrisWebDev
25

Karakter titik berarti cocok dengan karakter apa pun, jadi .*berarti nol atau lebih kemunculan karakter apa pun. Anda mungkin bermaksud menggunakan, .*bukan hanya *.

smcameron.dll
sumber
Titik adalah karakter meta yang menerima karakter apa pun kecuali baris baru .
Abhishek Kamal
12

"Tanda bintang" hanya bermakna jika ada sesuatu di depannya. Jika tidak ada alat (grep dalam kasus ini) mungkin akan memperlakukannya sebagai kesalahan. Sebagai contoh:

'*xyz'    is meaningless
'a*xyz'   means zero or more occurrences of 'a' followed by xyz
Jonathan Leffler
sumber
5
* Itu bukannya tidak berarti; itu hanya tidak memiliki arti yang biasa (pengulangan) tetapi berarti "Saya seorang bintang". Ini akan cocok dengan garis yang mengandung bintang diikuti oleh x, y, dan z.
Jonathan Leffler
2
@Jonathan Itu tergantung pada alatnya.
9

Gunakan grep -P - yang mengaktifkan dukungan untuk ekspresi reguler gaya Perl.

grep -P "abc.*def" myfile
Artem Russakovskii
sumber
6

Ekspresi yang Anda coba, seperti yang bekerja pada baris perintah shell di Linux misalnya, disebut " glob ". Ekspresi Glob bukanlah ekspresi reguler penuh , yang digunakan grep untuk menentukan string yang dicari. Berikut adalah postingan (lama, kecil) tentang perbedaannya. Ekspresi glob (seperti dalam "ls *") diinterpretasikan oleh shell itu sendiri.

Mungkin saja untuk menerjemahkan dari globs ke RE, tetapi Anda biasanya perlu melakukannya di kepala Anda.

beristirahat
sumber
1
Ini hanya berbentuk bola jika diurai oleh cangkangnya. Karena dia mempertahankan string pencarian di dalam tanda kutip tunggal, shell meninggalkan string itu sendiri, dan meneruskannya secara utuh di argv ke grep.
Penyusun yang Mencolok
4

Anda tidak menggunakan ekspresi reguler, jadi varian grep pilihan Anda haruslah fgrep, yang akan berperilaku seperti yang Anda harapkan.

Andrew Beals
sumber
2
fgrepsekarang tidak digunakan lagi, grep -fsebaiknya digunakan sebagai gantinya.
Prometheus
1
Itu adalah "grep -F". Orang tua yang baik mungkin "tidak digunakan lagi", tapi mereka tidak akan mengambilnya saat aku masih hidup.
Andrew Beals
1

Ini mungkin jawaban yang Anda cari:

grep abc MyFile | grep def

Hanya masalahnya ... itu akan mengeluarkan baris "def" sebelum ATAU setelah "abc"

Charles Duke
sumber
1

Ini berhasil untuk saya:

grep ". * $ {expr}" - dengan tanda kutip ganda, diawali dengan titik. Di mana "expr" adalah string apa pun yang Anda butuhkan di akhir baris.

Unix grep standar tanpa sakelar tambahan.

access_granted
sumber
0

'*' berfungsi sebagai pengubah untuk item sebelumnya. Jadi 'abc * def' mencari 'ab' diikuti oleh 0 atau lebih 'c's diikuti dengan' def '.

Yang mungkin Anda inginkan adalah 'abc. * Def' yang mencari 'abc' diikuti dengan sejumlah karakter, diikuti dengan 'def'.

Penyusun yang mencolok
sumber