grep -P ya no funciona. ¿Cómo puedo reescribir mis búsquedas?

99

Parece que la nueva versión de OSX ya no es compatible grep -Py, como tal, ha hecho que algunos de mis scripts dejen de funcionar.

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

Necesito capturar el grep en una variable y necesito usar las aserciones de ancho cero, así como \K

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

Cualquier alternativa será muy apreciada.

kugyousha
fuente
8
¿qué tal instalar gnu grep?
Kent
¿Estás seguro de que es el -P? El mío lo tiene.
Kevin
4
@Kevin Se eliminó en 10.8.
Lri
8
@ AdrianFrühwirth OS X en greprealidad cambió de grep (GNU grep) 2.5.110.7 a grep (BSD grep) 2.5.1-FreeBSD10.8. Supongo que fue por GPL. FreeBSD greptambién está basado en GNU grepy ambas versiones de grep2002. --labely -u/ --unix-byte-offetstambién fueron eliminadas en 10.8. -z/ --decompress, -J/ --bz2decompress, --exclude-dir, --include-dir, -S, -O, Y -pse añadieron en 10,8. -Zcambiado de --nulla --decompress.
Lri
3
El FreeBSD grepque viene con OS X es de 2002, y wiki.freebsd.org/BSDgrep todavía dice que "el único elemento de TODO es mejorar el rendimiento", así que sí. time grep aa /usr/share/dict/words>/dev/nulltoma aproximadamente 0.09 segundos con el grep de OS X y aproximadamente 0.01 segundos con un nuevo grep GNU en ejecuciones repetidas en mi iMac.
Lri

Respuestas:

68

Si quiere hacer la mínima cantidad de trabajo, cambie

grep -P 'PATTERN' file.txt

a

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

y cambio

grep -o -P 'PATTERN' file.txt

a

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

Entonces obtienes:

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`

En su caso específico, puede lograr un código más simple con trabajo adicional.

var1=`perl -nle'print for m{<st:italic>(.*)</italic>}g' file.txt`
var2=`perl -nle'print for /property:(.*\d+)end/g' file.txt`
ikegami
fuente
1
Esto funciona muy bien, pero devuelve todas las coincidencias, ya que el grep que usé solo devolvió la primera coincidencia. ¿Alguna idea de cómo devolver solo el primer partido?
kugyousha
1
@ironintention: agregar | tail -1al final de la canalización.
Peter
grepsiempre devuelve todas las líneas coincidentes (a menos que use una de las opciones donde no imprime ninguna). De todos modos, if (/.../) { print $1; last; }hará que solo imprima la primera coincidencia.
ikegami
Usé esto para obtener las URL de un mapa del sitio; gracias amigo, ¡no lo hubiera logrado sin tu publicación! perl -nle'print $ 1 if m {<loc> (. *) </loc>} 'sitemap.xml
Christian
2
@Christian, solo tomaría 3 líneas para hacerlo con un analizador XML adecuado como XML :: LibXML. (Línea Clave: say $_->textContent for $doc->findnodes('//loc');)
Ikegami
93

Si las secuencias de comandos son para un solo uso, se puede instalar grepdesde homebrew-coreel uso de brew:

brew install grep 

Entonces está disponible como ggrep(GNU grep). no reemplaza el sistema grep(debe colocar el grep instalado antes que el del sistema PATH).

La versión instalada por brewincluye la -Popción, por lo que no necesita cambiar sus scripts.

Si necesita usar estos comandos con sus nombres normales, puede agregar un directorio "gnubin" a su PATH desde su bashrc como:

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

Puede exportar esta línea en su ~ / .bashrc o ~ / .zshrc para conservarla para nuevas sesiones.

Consulte aquí para ver una discusión de los pros y los contras de la --with-default-namesopción anterior y su eliminación (reciente).

drevicko
fuente
3
@pepper ¿qué no funcionó? Es probable que la ruta no esté configurada correctamente: ¿cuál es el resultado which grep? Debería ser /usr/local/bin/grep. ¡Es un poco malo votar en contra antes de comprobar cuidadosamente que hay un problema!
drevicko
2
probablemente sea mejor agregarlo /usr/local/binal frente de su PATH. ¿Se supone que Brew configura eso, creo? ¿Usaste --default-names? De todos modos, me alegro de que funcione (: No estoy seguro de hackearlo, pero creo que el sistema de puntos es una de las razones por las que este sitio es un recurso tan bueno.
drevicko
1
sí, usé --default-names y brew. No estoy seguro de si poner / usr / local / bin al principio de su ruta es mejor que un alias, solo una alternativa
pimienta
10
una alternativa --with-default-nameses agregarlo alias grep='ggrep'a su perfil de bash y dejar que los embaucadores de cerveza mantengan su prefijo
rymo
4
--with-default-namesse retira de la preparación. Tenía que brew install grepconseguir ggrep y luego hacer lo que @rymo dice y hace alias grep='ggrep'.
Henge
12

Instale ack y utilícelo en su lugar. Ack es un reemplazo de grep escrito en Perl. Tiene soporte completo para expresiones regulares de Perl.

Michael Carman
fuente
Me gustaría verificar esto, pero esto es para computadoras de trabajo, por lo que no podemos instalar nada.
kugyousha
@ironintention: Si puede instalar módulos Perl, está bien. Incluso si no puede agregar a la instalación local de Perl, siempre puede usar local :: lib.
Michael Carman
ackestá diseñado para ser autónomo; no es necesario que lo instales. Si puede guardar un archivo, marcarlo como ejecutable y actualizarlo PATHsi es necesario, ya está listo.
tripleee
¿Puede complacer la sintaxis ack que reemplaza a la anterior
William Entriken
@FullDecent: Es casi idéntico: ack -o '(property:)\K.*\d+(?=end)' file.txt( -osignifica lo mismo, pero no necesitas el -Pcon ack)
Michael Carman
11

OS X tiende a proporcionar BSD en lugar de herramientas GNU. Que no vienen con egrepsin embargo, que es probablemente todo lo que necesita para llevar a cabo búsquedas de expresiones regulares.

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

Un fragmento de la página del manual grep de OSX:

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

nebuloso
fuente
5
La invocación directa como egrep está en desuso. La misma capacidad también está disponible como grep -E. Es ... una triste sombra de Perl, que carece de aseveraciones, la mayoría de los escapes de barra invertida, opciones, condicionales, etc. :( Los usuarios avanzados lo odiarán, pero al menos hace el trabajo.
Dewi Morgan
1
Gracias. grep -Een lugar de grep -Pera exactamente lo que necesitaba.
asmaier
6

use perl;

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

Si necesita más grepopciones (veo que -oal menos le gustaría ), hay varias pgrepimplementaciones flotando en la red, muchas de ellas en Perl.

Si "casi Perl" es lo suficientemente bueno, PCRE incluye pcregrep.

triples
fuente
5

No hay otra alternativa: pcregrep.

Pcregrep es un grep con expresiones regulares compatibles con Perl. Tiene exactamente el mismo uso que grep -P. Entonces será compatible con tus scripts.

Se puede instalar con homebrew:

brew install pcre

Gabor Marton
fuente
Error: No available formula for pcregrep
Aaron Brager
GaborMarton, edité su respuesta para incluir el comentario de corrección de @Martin, y tuve que cambiar un poco el formato para superar los cambios mínimos.
Daniel Baird
3

¿Qué tal usar la opción '-E'? Funciona bien para mí, por ejemplo, si quiero comprobar si hay una php_zip, php_xml, php_gd2la extensión de php -m uso I:

php -m | grep -E '(zip|xml|gd2)'
ZenC
fuente
1
esto funciona. Mac usa FreeBSD grep y Linux usa GNU grep ... así que esta solución funcionó en mi macOS sierra
jimh
2

Equivalente a la respuesta aceptada, pero sin el requisito del interruptor -P, que no estaba presente en las dos máquinas que tenía disponibles.

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

Este funcionó para mí:

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

Otra solución de Perl para -P

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

use la expresión regular de una línea de perl pasando la salida de búsqueda con una tubería. Solía búsqueda hacia atrás (obtener src enlaces en html) y la búsqueda hacia delante para " y pasé la salida de rizo (html) a la misma.

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
fuente