grep -P tidak lagi berfungsi. Bagaimana cara menulis ulang pencarian saya?

99

Sepertinya versi baru OSX tidak lagi mendukung grep -Pdan karena itu telah membuat beberapa skrip saya berhenti berfungsi.

var1=`grep -o -P '(?<=<st:italic>).*(?=</italic>)' file.txt`

Saya perlu menangkap grep ke variabel dan saya perlu menggunakan pernyataan lebar nol, juga \K

var2=`grep -P -o '(property:)\K.*\d+(?=end)' file.txt`

Alternatif apa pun akan sangat dihargai.

kugyousha
sumber
8
Bagaimana kalau menginstal gnu grep?
Kent
Apakah kamu yakin itu -P? Punyaku memilikinya.
Kevin
4
@Kevin Ini telah dihapus pada 10.8.
Lri
8
@ AdrianFrühwirth OS X grepsebenarnya berubah dari grep (GNU grep) 2.5.110.7 menjadi grep (BSD grep) 2.5.1-FreeBSD10.8. Saya kira itu karena GPL. FreeBSD grepjuga berdasarkan GNU grepdan kedua versi grepdari 2002. --labeldan -u/ --unix-byte-offetsjuga dihapus pada 10.8. -z/ --decompress, -J/ --bz2decompress, --exclude-dir, --include-dir, -S, -O, Dan -pditambahkan di 10,8. -Zdiubah dari --nullmenjadi --decompress.
Lri
3
FreeBSD grepyang disertakan dengan OS X berasal dari tahun 2002, dan wiki.freebsd.org/BSDgrep masih mengatakan bahwa "satu-satunya item TODO adalah meningkatkan kinerja", jadi ya. time grep aa /usr/share/dict/words>/dev/nullmembutuhkan sekitar 0,09 detik dengan grep OS X dan sekitar 0,01 detik dengan grep GNU baru saat berjalan berulang kali di iMac saya.
Lri

Jawaban:

68

Jika Anda ingin melakukan sedikit pekerjaan, ubahlah

grep -P 'PATTERN' file.txt

untuk

perl -nle'print if m{PATTERN}' file.txt

dan berubah

grep -o -P 'PATTERN' file.txt

untuk

perl -nle'print $& while m{PATTERN}g' file.txt

Jadi Anda mendapatkan:

var1=`perl -nle'print $& while m{(?<=<st:italic>).*(?=</italic>)}g' file.txt`
var2=`perl -nle'print $& while m{(property:)\K.*\d+(?=end)}g' file.txt`

Dalam kasus khusus Anda, Anda dapat mencapai kode yang lebih sederhana dengan pekerjaan ekstra.

var1=`perl -nle'print for m{<st:italic>(.*)</italic>}g' file.txt`
var2=`perl -nle'print for /property:(.*\d+)end/g' file.txt`
ikegami
sumber
1
Ini berfungsi dengan baik tetapi mengembalikan semua kecocokan karena grep yang saya gunakan hanya mengembalikan kecocokan pertama. ada ide tentang bagaimana mengembalikan hanya pertandingan pertama?
kugyousha
1
@ironintention: tambahkan | tail -1ke ujung pipeline.
Peter
grepselalu mengembalikan semua baris yang cocok (kecuali jika Anda menggunakan salah satu opsi yang tidak mencetak sama sekali). Bagaimanapun, if (/.../) { print $1; last; }akan menyebabkannya hanya mencetak pertandingan pertama.
ikegami
Saya menggunakan ini untuk mengeluarkan url peta situs - terima kasih sobat, tidak akan berhasil tanpa posting Anda! perl -nle'print $ 1 if m {<loc> (. *) </loc>} 'sitemap.xml
Christian
2
@Christian, Hanya membutuhkan 3 baris untuk melakukannya dengan parser XML yang tepat seperti XML :: LibXML. (Baris Key: say $_->textContent for $doc->findnodes('//loc');)
ikegami
93

Jika skrip Anda hanya untuk Anda gunakan, Anda dapat menginstal grepdari homebrew-coremenggunakan brew:

brew install grep 

Kemudian tersedia sebagai ggrep(GNU grep). itu tidak menggantikan sistem grep(Anda harus meletakkan grep yang diinstal sebelum sistem di PATH).

Versi yang diinstal oleh brewmenyertakan-P opsi, jadi Anda tidak perlu mengubah skrip Anda.

Jika Anda perlu menggunakan perintah ini dengan nama normalnya, Anda dapat menambahkan direktori "gnubin" ke PATH Anda dari bashrc seperti:

PATH="/usr/local/opt/grep/libexec/gnubin:$PATH"

Anda dapat mengekspor baris ini di ~ / .bashrc atau ~ / .zshrc Anda untuk menyimpannya untuk sesi baru.

Silakan lihat di sini untuk diskusi tentang pro dan kontra dari --with-default-namesopsi lama dan penghapusan (baru-baru ini).

drevicko
sumber
3
@ lada apa yang tidak berhasil? Kemungkinan jalur tidak disetel dengan benar - apa outputnya which grep? Seharusnya /usr/local/bin/grep. Sedikit bermaksud untuk memberi suara negatif sebelum Anda memeriksa dengan cermat bahwa ada masalah!
drevicko
2
mungkin lebih baik untuk menambahkan /usr/local/binbagian depan PATH Anda. Bir seharusnya mengaturnya, saya percaya? Apakah Anda menggunakan --default-names? Bagaimanapun, senang itu berhasil (: Tidak yakin tentang peretasan di sekitarnya, tetapi saya pikir sistem poin adalah salah satu alasan mengapa situs ini adalah sumber daya yang baik.
drevicko
1
ya saya memang menggunakan --default-names and brew. Tidak yakin apakah meletakkan / usr / local / bin di depan jalur Anda lebih baik daripada alias, hanya alternatif
lada
10
alternatifnya --with-default-namesadalah menambahkan alias grep='ggrep'ke profil bash Anda dan membiarkan pembuat minuman menipu tetap menggunakan awalan mereka
rymo
4
--with-default-namesdihapus dari minuman. Saya harus brew install grepmendapatkan ggrep dan kemudian melakukan apa yang @rymo katakan dan lakukan alias grep='ggrep'.
Henge
12

Instal ack dan gunakan sebagai gantinya. Ack adalah pengganti grep yang ditulis di Perl. Ini memiliki dukungan penuh untuk ekspresi reguler Perl.

Michael Carman
sumber
Saya ingin memeriksanya tetapi ini untuk komputer kerja jadi kami tidak dapat menginstal apa pun
kugyousha
@ironintention: Jika Anda dapat menginstal modul Perl, Anda bagus. Meskipun Anda tidak dapat menambahkan ke instalasi Perl lokal, Anda selalu dapat menggunakan local :: lib.
Michael Carman
ackdirancang untuk menjadi mandiri; Anda tidak perlu menginstalnya. Jika Anda dapat menyimpan file, tandai sebagai exectutable, dan perbarui PATHjika perlu, Anda siap melakukannya.
tripleee
Bisakah Anda menyenangkan sintaks ack yang menggantikan di atas
William Entriken
@FullDecent: Ini hampir identik: ack -o '(property:)\K.*\d+(?=end)' file.txt( -oartinya sama, tetapi Anda tidak perlu -Pdengan ack)
Michael Carman
11

OS X cenderung menyediakan alat BSD daripada GNU. Itu memang datang dengan egrep, yang mungkin saja Anda butuhkan untuk melakukan pencarian regex.

contoh: egrep 'fo+b?r' foobarbaz.txt

Cuplikan dari halaman manual grep OSX:

grep is used for simple patterns and basic regular expressions (BREs); egrep can handle extended regular expressions (EREs).

samar
sumber
5
Doa langsung sebagai egrep tidak digunakan lagi. Kemampuan yang sama juga tersedia sebagai grep -E. Itu ... bayangan menyedihkan dari Perl, tidak memiliki penegasan yang mencari, sebagian besar pelarian garis miring terbalik, opsi, kondisional, dll :( Pengguna yang kuat akan membencinya, tetapi setidaknya melakukan pekerjaan itu.
Dewi Morgan
1
Terima kasih. grep -Ebukan grep -Papa yang saya butuhkan.
asmaier
6

use perl;

perl -ne 'print if /regex/' files ...

Jika Anda membutuhkan lebih banyak grepopsi (saya melihat Anda ingin -osetidaknya) ada berbagai pgrepimplementasi yang mengambang di internet, banyak di antaranya di Perl.

Jika "hampir Perl" cukup baik, PCRE dikirimkan bersama pcregrep.

tripleee
sumber
5

Ada alternatif lain: pcregrep .

Pcregrep adalah grep dengan ekspresi reguler yang kompatibel dengan Perl. Ini memiliki penggunaan yang sama persis dengangrep -P . Jadi itu akan kompatibel dengan skrip Anda.

Itu dapat diinstal dengan homebrew:

brew install pcre

Gabor Marton
sumber
Error: No available formula for pcregrep
Aaron Brager
GaborMarton, saya mengedit jawaban Anda untuk menyertakan komentar koreksi @Martin, dan harus mengubah sedikit format untuk mengatasi perubahan minimum.
Daniel Baird
3

Bagaimana jika menggunakan opsi '-E'? Ia bekerja dengan baik bagi saya, misalnya, jika saya ingin memeriksa untuk php_zip, php_xml, php_gd2ekstensi dari php-m saya gunakan:

php -m | grep -E '(zip|xml|gd2)'
ZenC
sumber
1
ini bekerja. Mac menggunakan FreeBSD grep dan Linux menggunakan GNU grep ... jadi perbaikan ini berfungsi pada macOS sierra saya
jimh
2

Setara dengan jawaban yang diterima, tetapi tanpa persyaratan sakelar -P, yang tidak ada di kedua mesin yang saya miliki.

find . -type f -exec perl -nle 'print $& if m{\r\n}' {} ';' -exec perl -pi -e 's/\r\n/\n/g' {} '+'
nuzzolilo
sumber
2

Yang ini berhasil untuk saya:

    awk  -F":" '/PATTERN/' file.txt
petegam
sumber
0

Solusi Perl lain untuk -P

var1=$( perl -ne 'print $1 if m#<st:italic>([^<]+)</st:italic># ' file.txt)
Rory Hunter
sumber
0

menggunakan regex satu baris perl dengan melewatkan keluaran find dengan sebuah pipa. Saya menggunakan lookbehind (dapatkan link src di html) dan lookahead untuk " dan meneruskan keluaran curl (html) padanya.

bash-3.2# curl stackoverflow.com | perl -0777 -ne '$a=1;while(m/(?<=src\=\")(.*)(?=\")/g){print "Match #".$a." "."$&\n";$a+=1;}'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  239k  100  239k    0     0  1911k      0 --:--:-- --:--:-- --:--:-- 1919k
Match #1 //ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js
Match #2 //cdn.sstatic.net/Js/stub.en.js?v=fb6157e02696
Match #3 https://ssum-sec.casalemedia.com/usermatch?s=183712&amp;cb=https%3A%2F%2Fengine.adzerk.net%2Fudb%2F22%2Fsync%2Fi.gif%3FpartnerId%3D1%26userId%3D
Match #4 //i.stack.imgur.com/817gJ.png" height="16" width="18" alt="" class="sponsor-tag-img">elasticsearch</a> <a href="/questions/tagged/elasticsearch-2.0" class="post-tag" title="show questions tagged &#39;elasticsearch-2.0&#39;" rel="tag">elasticsearch-2.0</a> <a href="/questions/tagged/elasticsearch-dsl" class="post-tag" title="show questions tagged &#39;elasticsearch-dsl&#39;" rel="tag
Match #5 //i.stack.imgur.com/817gJ.png" height="16" width="18" alt="" class="sponsor-tag-img">elasticsearch</a> <a href="/questions/tagged/sharding" class="post-tag" title="show questions tagged &#39;sharding&#39;" rel="tag">sharding</a> <a href="/questions/tagged/master" class="post-tag" title="show questions tagged &#39;master&#39;" rel="tag
Match #6 //i.stack.imgur.com/tKsDb.png" height="16" width="18" alt="" class="sponsor-tag-img">android</a> <a href="/questions/tagged/linux" class="post-tag" title="show questions tagged &#39;linux&#39;" rel="tag">linux</a> <a href="/questions/tagged/camera" class="post-tag" title="show questions tagged &#39;camera&#39;" rel="tag
Match #7 //i.stack.imgur.com/tKsDb.png" height="16" width="18" alt="" class="sponsor-tag-img">android</a> <a href="/questions/tagged/firebase" class="post-tag" title="show questions tagged &#39;firebase&#39;" rel="tag"><img src="//i.stack.imgur.com/5d55j.png" height="16" width="18" alt="" class="sponsor-tag-img">firebase</a> <a href="/questions/tagged/firebase-authentication" class="post-tag" title="show questions tagged &#39;firebase-authentication&#39;" rel="tag
Match #8 //i.stack.imgur.com/tKsDb.png" height="16" width="18" alt="" class="sponsor-tag-img">android</a> <a href="/questions/tagged/ios" class="post-tag" title="show questions tagged &#39;ios&#39;" rel="tag">ios</a> <a href="/questions/tagged/in-app-purchase" class="post-tag" title="show questions tagged &#39;in-app-purchase&#39;" rel="tag">in-app-purchase</a> <a href="/questions/tagged/piracy-protection" class="post-tag" title="show questions tagged &#39;piracy-protection&#39;" rel="tag
Match #9 //i.stack.imgur.com/tKsDb.png" height="16" width="18" alt="" class="sponsor-tag-img">android</a> <a href="/questions/tagged/unity3d" class="post-tag" title="show questions tagged &#39;unity3d&#39;" rel="tag">unity3d</a> <a href="/questions/tagged/vr" class="post-tag" title="show questions tagged &#39;vr&#39;" rel="tag
Match #10 http://pixel.quantserve.com/pixel/p-c1rF4kxgLUzNc.gif" alt="" class="dno
bash-3.2# date
Mon Oct 24 20:57:11 EDT 2016
Rohit Malgaonkar
sumber