grep -P ne fonctionne plus. Comment réécrire mes recherches?


99

Il semble que la nouvelle version d'OSX ne prend plus en charge grep -P et que certains de mes scripts cessent de fonctionner.

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

J'ai besoin de capturer le grep dans une variable et je dois utiliser les assertions de largeur zéro, ainsi que \K

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

Toute alternative serait grandement appréciée.


8
que diriez-vous d'installer gnu grep?
Kent

Êtes-vous sûr que c'est le -P? Le mien l'a.
Kevin

4
@Kevin Il a été supprimé en 10.8.
Lri

8
@ AdrianFrühwirth OS X est en grepfait passé de grep (GNU grep) 2.5.110.7 à grep (BSD grep) 2.5.1-FreeBSD10.8. Je suppose que c'était à cause de la GPL. FreeBSD grepest également basé sur GNU grepet les deux versions de grepdatent de 2002. --labelet -u/ --unix-byte-offetsont également été supprimées dans la version 10.8. -z/ --decompress, -J/ --bz2decompress, --exclude-dir, --include-dir, -S, -OEt -pont été ajoutés à 10,8. -Zchangé de --nullà --decompress.
Lri

3
Le FreeBSD grepfourni avec OS X date de 2002, et wiki.freebsd.org/BSDgrep dit toujours que "le seul élément TODO est d'améliorer les performances", alors oui. time grep aa /usr/share/dict/words>/dev/nullprend environ 0,09 seconde avec le grep d'OS X et environ 0,01 seconde avec un nouveau grep GNU lors d'exécutions répétées sur mon iMac.
Lri

Réponses:


68

Si vous voulez faire le minimum de travail, changez

grep -P 'PATTERN' file.txt

à

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

et changer

grep -o -P 'PATTERN' file.txt

à

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

Donc vous obtenez:

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`

Dans votre cas spécifique, vous pouvez obtenir un code plus simple avec un travail supplémentaire.

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

1
Cela fonctionne très bien mais il renvoie toutes les correspondances comme où le grep que j'ai utilisé n'a renvoyé que la première correspondance. une idée sur la façon de ne renvoyer que le premier match?
kugyousha

1
@ironintention: ajouter | tail -1à la fin du pipeline.
Peter

greprenvoie toujours toutes les lignes correspondantes (sauf si vous utilisez l'une des options où il n'en imprime aucune). Quoi qu'il en soit, if (/.../) { print $1; last; }il n'imprimera que la première correspondance.
ikegami du

Je l'ai utilisé pour sortir les URL d'un plan de site - merci mon pote, je ne l'aurais pas fait sans votre message! perl -nle'print $ 1 if m {<loc> (. *) </loc>} 'sitemap.xml
Christian

2
@Christian, ne prendrait que 3 lignes pour le faire avec un analyseur XML approprié tel que XML :: LibXML. (Ligne clé: say $_->textContent for $doc->findnodes('//loc');)
Ikegami

93

Si vos scripts sont uniquement pour votre usage, vous pouvez installer à greppartir à l' homebrew-coreaide brew:

brew install grep 

Ensuite, il est disponible en tant que ggrep(GNU grep). il ne remplace pas le système grep(vous devez mettre le grep installé avant celui du système sur le PATH).

La version installée par brewinclut le-P option, vous n'avez donc pas besoin de modifier vos scripts.

Si vous avez besoin d'utiliser ces commandes avec leurs noms normaux, vous pouvez ajouter un répertoire "gnubin" à votre PATH depuis votre bashrc comme:

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

Vous pouvez exporter cette ligne sur votre ~ / .bashrc ou ~ / .zshrc pour la conserver pour les nouvelles sessions.

Veuillez consulter ici pour une discussion des avantages et des inconvénients de l'ancienne --with-default-namesoption et de sa suppression (récente).


3
@pepper qu'est-ce qui n'a pas fonctionné? Le chemin n'est probablement pas défini correctement - quel est le résultat which grep? Devrait être /usr/local/bin/grep. C'est un peu méchant de voter avant d'avoir vérifié soigneusement qu'il y a un problème!
drevicko

2
probablement préférable d'ajouter /usr/local/binau début de votre PATH. Brew est censé mettre ça en place, je crois? Avez-vous utilisé --default-names? Quoi qu'il en soit, content que cela fonctionne (: Je ne suis pas sûr de pirater autour de lui, mais je pense que le système de points est l'une des raisons pour lesquelles ce site est une si bonne ressource.
drevicko

1
oui j'ai utilisé --default-names and Brew. Je ne sais pas si mettre / usr / local / bin devant votre chemin est meilleur qu'un alias, juste une alternative
pepper

10
une alternative à --with-default-namesest d'ajouter alias grep='ggrep'à votre profil bash et de laisser les dupes de bière conserver leur préfixe
rymo

4
--with-default-namesest retiré de l'infusion. Je devais brew install grepobtenir ggrep puis faire comme @rymo dit et faire alias grep='ggrep'.
Henge

12

Installez ack et utilisez-le à la place. Ack est un remplacement de grep écrit en Perl. Il prend totalement en charge les expressions régulières Perl.


J'aimerais vérifier cela, mais c'est pour les ordinateurs de travail, nous ne pouvons donc rien installer
kugyousha

@ironintention: Si vous pouvez installer des modules Perl, c'est bon. Même si vous ne pouvez pas ajouter à l'installation locale de Perl, vous pouvez toujours utiliser local :: lib.
Michael Carman

ackest conçu pour être autonome; vous n'avez pas besoin de l'installer. Si vous pouvez enregistrer un fichier, le marquer comme exécutable et le mettre à jour PATHsi nécessaire, vous êtes prêt à partir.
tripleee

Pouvez-vous s'il vous plaît la syntaxe d'ack qui remplace ce qui précède
William Entriken

@FullDecent: C'est presque identique: ack -o '(property:)\K.*\d+(?=end)' file.txt( -osignifie la même chose, mais vous n'avez pas besoin du -Pavec ack)
Michael Carman

11

OS X a tendance à fournir des outils BSD plutôt que GNU. Il ne vient avecegrep cependant, ce qui est probablement tout ce que vous devez effectuer des recherches regex.

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

Un extrait de la page de manuel OSX grep:

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


5
L'appel direct comme egrep est obsolète. La même capacité est également disponible en tant que grep -E. C'est ... une triste ombre de Perl, sans assertions de recherche, la plupart des échappements de backslash, des options, des conditions, etc.: (Les utilisateurs expérimentés le détesteront, mais il fait au moins le travail.
Dewi Morgan

1
Merci. grep -Eau lieu de grep -Pc'était exactement ce dont j'avais besoin.
asmaier le

6

use perl;

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

Si vous avez besoin de plus d' grepoptions (je vois que vous aimeriez -oau moins), il existe plusieurspgrep implémentations flottant sur le net, dont beaucoup en Perl.

Si "presque Perl" est assez bon, PCRE est livré avec pcregrep.


5

Il existe une autre alternative: pcregrep.

Pcregrep est un grep avec des expressions régulières compatibles Perl. Il a exactement le même usage que grep -P. Il sera donc compatible avec vos scripts.

Il peut être installé avec homebrew:

brew install pcre


Error: No available formula for pcregrep
Aaron Brager du

GaborMarton, j'ai modifié votre réponse pour inclure le commentaire de correction de @Martin, et j'ai dû déplacer un peu la mise en forme pour surmonter les changements minimaux.
Daniel Baird

3

Que diriez-vous d'utiliser l'option «-E»? Il fonctionne très bien pour moi, par exemple, si je veux vérifier un php_zip, php_xml, l' php_gd2extension de php -m utilisation I:

php -m | grep -E '(zip|xml|gd2)'

1
cela marche. Mac utilise FreeBSD grep et Linux utilise GNU grep ... donc ce correctif a fonctionné sur mon macOS sierra
jimh

2

Équivalent de la réponse acceptée, mais sans l'exigence du commutateur -P, qui n'était pas présent sur les deux machines dont j'avais à disposition.

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

2

Celui-ci a fonctionné pour moi:

    awk  -F":" '/PATTERN/' file.txt

0

Une autre solution Perl pour -P

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

0

utilisez l'expression rationnelle perl one-liner en passant la sortie find avec un tube. J'ai utilisé lookbehind (obtenir les liens src en html) et lookahead pour " et lui ai transmis la sortie de curl (html).

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.