grep -P funktioniert nicht mehr. Wie kann ich meine Suchanfragen umschreiben?


90

Es sieht so aus, als würde die neue Version von OSX nicht mehr unterstützt grep -Pund einige meiner Skripte funktionieren daher nicht mehr .

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

Ich muss das grep in einer Variablen erfassen und ich muss auch die Zusicherungen mit der Breite Null verwenden \K

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

Alle Alternativen wäre sehr dankbar.


7
Wie wäre es mit der Installation von Gnu Grep?
Kent

Bist du sicher, dass es das ist -P? Meins hat es.
Kevin

4
@ Kevin Es wurde in 10.8 entfernt.
Lri

8
@ AdrianFrühwirth OS X hat sich greptatsächlich von grep (GNU grep) 2.5.110.7 auf grep (BSD grep) 2.5.1-FreeBSD10.8 geändert . Ich denke, das lag an der GPL. Das FreeBSD grepbasiert ebenfalls auf GNU grepund beide Versionen von grepstammen aus dem Jahr 2002. --labelund -u/ --unix-byte-offetswurden ebenfalls in 10.8 entfernt. -z/ --decompress, -J/ --bz2decompress, --exclude-dir, --include-dir, -S, -O, Und -pwurden in 10,8 zugegeben. -Zgeändert von --nullzu --decompress.
Lri

3
Das grepmit OS X gelieferte FreeBSD stammt aus dem Jahr 2002, und wiki.freebsd.org/BSDgrep sagt immer noch, dass "das einzige TODO-Element die Verbesserung der Leistung ist", also ja. time grep aa /usr/share/dict/words>/dev/nulldauert mit OS X Grep ungefähr 0,09 Sekunden und mit einem neuen GNU Grep ungefähr 0,01 Sekunden bei wiederholten Läufen auf meinem iMac.
Lri

Antworten:


65

Wenn Sie den minimalen Arbeitsaufwand erledigen möchten, ändern Sie

grep -P 'PATTERN' file.txt

zu

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

und ändern

grep -o -P 'PATTERN' file.txt

zu

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

So bekommen Sie:

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`

In Ihrem speziellen Fall können Sie mit zusätzlicher Arbeit einfacheren Code erzielen.

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

1
Dies funktioniert hervorragend, gibt jedoch alle Übereinstimmungen zurück, da der von mir verwendete grep nur die erste Übereinstimmung zurückgegeben hat. Hast du eine Idee, wie du nur das erste Match zurückgeben kannst?
Kugyousha

1
@ironintention: | tail -1am Ende der Pipeline hinzufügen .
Peter

grepGibt immer alle übereinstimmenden Zeilen zurück (es sei denn, Sie verwenden eine der Optionen, bei denen überhaupt keine gedruckt werden). Auf jeden Fall if (/.../) { print $1; last; }wird nur die erste Übereinstimmung gedruckt.
Ikegami

Ich habe dies verwendet, um die URLs einer Sitemap herauszuholen - danke Kumpel, hätte es ohne deinen Beitrag nicht geschafft! perl -nle'print $ 1 if m {<loc> (. *) </ loc>} 'sitemap.xml
Christian

2
@Christian, würde nur 3 Zeilen benötigen, um dies mit einem geeigneten XML-Parser wie XML :: LibXML zu tun. (Key Zeile: say $_->textContent for $doc->findnodes('//loc');)
ikegami

89

Wenn Ihre Scripts nur für Ihren Gebrauch sind, können Sie installieren grepaus homebrew-coremit brew:

brew install grep 

Dann ist es als ggrep(GNU grep) verfügbar . Es ersetzt nicht das System grep(Sie müssen das installierte grep vor dem System eins auf dem platzieren PATH).

Die von installierte Version brewenthält die -POption, sodass Sie Ihre Skripte nicht ändern müssen.

Wenn Sie diese Befehle mit ihren normalen Namen verwenden müssen, können Sie Ihrem PATH aus Ihrem bashrc ein "gnubin" -Verzeichnis hinzufügen, wie:

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

Sie können diese Zeile in Ihr ~ / .bashrc oder ~ / .zshrc exportieren, um sie für neue Sitzungen beizubehalten.

Bitte beachten Sie hier für eine Diskussion über die pro-s und Nachteile der alten --with-default-namesOption und es ist (letzten) Entfernung.


3
@pepper was hat nicht funktioniert? Wahrscheinlich ist der Pfad nicht richtig eingestellt - was ist die Ausgabe von which grep? Sollte sein /usr/local/bin/grep. Es ist ein bisschen gemein, abzustimmen, bevor Sie sorgfältig geprüft haben, ob es ein Problem gibt!
Drevicko

2
wahrscheinlich besser, um /usr/local/bindie Vorderseite Ihres Pfades hinzuzufügen . Brew soll das einrichten, glaube ich? Hast du benutzt --default-names? Wie auch immer, ich bin froh, dass es funktioniert (: Ich bin mir nicht sicher, ob ich es
umgehen soll

1
ja ich habe --default-names verwendet und gebraut. Ich bin mir nicht sicher, ob es besser ist, / usr / local / bin an die Spitze Ihres Pfades zu setzen als einen Alias, nur eine Alternative
Pfeffer

9
Eine Alternative zu --with-default-namesist, alias grep='ggrep'zu Ihrem Bash-Profil hinzuzufügen und
Brew Dupes

4
--with-default-nameswird aus dem Gebräu entfernt. Ich musste brew install grepggrep bekommen und dann tun, was @rymo sagt und tut alias grep='ggrep'.
Henge

12

Installieren Sie ack und verwenden Sie es stattdessen. Ack ist ein in Perl geschriebener grep-Ersatz. Es bietet volle Unterstützung für reguläre Perl-Ausdrücke.


Ich würde das gerne überprüfen, aber dies ist für
Arbeitscomputer,

@ironintention: Wenn Sie Perl-Module installieren können, sind Sie gut. Auch wenn Sie der lokalen Perl-Installation nichts hinzufügen können, können Sie immer local :: lib verwenden.
Michael Carman

ackist so konzipiert, dass es in sich geschlossen ist; Sie müssen es nicht tatsächlich installieren. Wenn Sie eine Datei speichern, als ausführbar markieren und PATHbei Bedarf aktualisieren können, können Sie loslegen .
Tripleee

Können Sie bitte die ack-Syntax, die die oben genannten ersetzt
William Entriken

@FullDecent: Es ist fast identisch: ack -o '(property:)\K.*\d+(?=end)' file.txt( -obedeutet das gleiche, aber Sie brauchen das nicht -Pmit ack)
Michael Carman

11

OS X bietet eher BSD- als GNU-Tools. Es kommt mitegrep aber das ist wahrscheinlich alles , was Sie regex Suche durchführen müssen.

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

Ein Ausschnitt aus der OSX-Grep-Manpage:

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


5
Direkter Aufruf als egrep ist veraltet. Die gleiche Fähigkeit ist auch als grep -E verfügbar. Es ist ... ein trauriger Schatten von Perl, dem es an Lookaround-Behauptungen mangelt, die meisten Backslash-Fluchten, Optionen, Bedingungen usw .: (Power-User werden es hassen, aber es macht zumindest den Job.
Dewi Morgan

1
Vielen Dank. grep -Estattdessen grep -Pwar genau das, was ich brauchte.
Asmaier

6

use perl;

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

Wenn Sie mehr grepOptionen benötigen (ich sehe, dass Sie -ozumindest möchten ), gibt es verschiedene pgrepImplementierungen im Netz, viele davon in Perl.

Wenn "fast Perl" gut genug ist, wird PCRE mit ausgeliefert pcregrep.


5

Es gibt noch eine andere Alternative : pcregrep.

Pcregrep ist ein Grep mit Perl-kompatiblen regulären Ausdrücken. Es hat genau die gleiche Verwendung wie grep -P. So wird es mit Ihren Skripten kompatibel sein.

Es kann mit Homebrew installiert werden:

brew install pcre


Error: No available formula for pcregrep
Aaron Brager

GaborMarton, ich habe Ihre Antwort so bearbeitet, dass sie @Martins korrigierenden Kommentar enthält, und musste die Formatierung ein wenig verschieben, um die minimalen Änderungen zu überwinden.
Daniel Baird

3

Wie wäre es mit der Option '-E'? Es funktioniert gut für mich, zum Beispiel, wenn ich für ein überprüfen möchten php_zip, php_xml, php_gd2Erweiterung von PHP -m I Verwendung:

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

1
das funktioniert. Mac verwendet FreeBSD grep und Linux verwendet GNU grep ... also funktionierte dieses
Update

2

Entspricht der akzeptierten Antwort, jedoch ohne die Anforderung des -P-Schalters, der auf beiden Maschinen, die ich zur Verfügung hatte, nicht vorhanden war.

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

2

Dieser hat für mich gearbeitet:

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

0

Eine weitere Perl-Lösung für -P

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

0

Verwenden Sie den Perl-Einzeiler-Regex, indem Sie die Suchausgabe mit einer Pipe übergeben. Ich habe lookbehind (get src links in html) und lookahead for "verwendet und die Ausgabe von curl (html) an sie übergeben.

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="/programming/tagged/elasticsearch-2.0" class="post-tag" title="show questions tagged &#39;elasticsearch-2.0&#39;" rel="tag">elasticsearch-2.0</a> <a href="/programming/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="/programming/tagged/sharding" class="post-tag" title="show questions tagged &#39;sharding&#39;" rel="tag">sharding</a> <a href="/programming/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="/programming/tagged/linux" class="post-tag" title="show questions tagged &#39;linux&#39;" rel="tag">linux</a> <a href="/programming/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="/programming/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="/programming/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="/programming/tagged/ios" class="post-tag" title="show questions tagged &#39;ios&#39;" rel="tag">ios</a> <a href="/programming/tagged/in-app-purchase" class="post-tag" title="show questions tagged &#39;in-app-purchase&#39;" rel="tag">in-app-purchase</a> <a href="/programming/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="/programming/tagged/unity3d" class="post-tag" title="show questions tagged &#39;unity3d&#39;" rel="tag">unity3d</a> <a href="/programming/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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.