Forzar a Bash a usar el motor Perl RegEx

11

Como ya sabrá, el motor Bash RegEx no admite muchas de las características que admiten los motores RegEx modernos (referencias anteriores, afirmaciones de búsqueda, etc.). El siguiente es un script Bash simple que acabo de crear para tratar de explicar cuál es mi objetivo final:

#!/bin/bash

# Make sure exactly two arguments are passed.
if [ $# -lt 2 ]
then
    echo "Usage: match [string] [pattern]"
    return
fi

variable=${1}
pattern=${2}

if [[ ${variable} =~ ${pattern} ]]
then
    echo "true"
else
    echo "false"
fi

Entonces, por ejemplo, algo como el siguiente comando devolverá falso:

. match.sh "catfish" "(?=catfish)fish"

mientras que la misma expresión exacta encontrará una coincidencia cuando se usa en un Perl o un JavaScript regex tester.

Las referencias posteriores (p. Ej. (Expr1) (expr2) [] \ 1 \ 2) tampoco coincidirán.

Simplemente he llegado a la conclusión de que mi problema solo se resolverá cuando obligue a bash a usar un motor RegEx compatible con Perl. ¿Es esto factible? Si es así, ¿cómo haría para realizar el procedimiento?

Fadi Hanna AL-Kass
fuente
55
¿Por qué no solo usas perl en lugar de bash para crear scripts? ¿Y por qué esta pregunta está etiquetada con JavaScript?
Marco
Porque usar Bash es imprescindible en mi situación. Y he etiquetado accidentalmente JavaScript. Lo eliminé :)
Fadi Hanna AL-Kass
2
¿Por qué no se utiliza grepcon -Po usar sed?
Cuonglm
2
Pero nunca explica la situación / problema que lo llevó a la conclusión de que debe hacer que el shell haga algo que simplemente no puede hacer. Habría una mejor manera.
llua
Encuentro que backreferences hacer el trabajo en bash 4.3.x (Ubuntu 14.04), pero no en bash 3.2x (OS X). Aquí está mi comando de prueba:re="([a-z])[0-9]\1"; [[ a1a =~ $re ]] && echo ${BASH_REMATCH[0]}
Digital Trauma

Respuestas:

14

Bash no admite un método para hacer esto en este momento. Te quedan las siguientes opciones:

  1. Usa Perl
  2. Utilizar grep [-P|--perl-regexp]
  3. Use la funcionalidad Bash para codificarlo

Creo que iría con el # 2 y trataría de usarlo greppara obtener lo que quiero funcionalmente. Para las referencias anteriores, puede hacer lo siguiente con grep:

$ echo 'BEGIN `helloworld` END' | grep -oP '(?<=BEGIN `).*(?=` END)'
helloworld

-o, --only-matching       show only the part of a line matching PATTERN
-P, --perl-regexp         PATTERN is a Perl regular expression

(?=pattern)
    is a positive look-ahead assertion
(?!pattern)
    is a negative look-ahead assertion
(?<=pattern)
    is a positive look-behind assertion
(?<!pattern)
    is a negative look-behind assertion 

Referencias

slm
fuente
Sinceramente, no sabía que grep tenía una [-P|--perl-regexp]ficha. Muchas gracias :-)
Fadi Hanna AL-Kass
@ FadiHannaAL-Kass: de nada. Gracias por la pregunta
slm
2
Para la posteridad, solo GNU grep incluye la -Popción, y no es universal. El grep de FreeBSD se basa en GNU, pero la documentación dice "Esta opción no es compatible con FreeBSD". En OSX, grep también se basa en GNU, pero la -Popción ni siquiera se menciona en la página del manual. Y en otros sistemas Unix cuyo grep no es GNU, es poco probable que veas -Palgún lugar. Si existe la posibilidad remota de que la portabilidad pueda serle útil en el futuro, le recomiendo evitar opciones específicas del sistema operativo como esta.
ghoti
pcregrepTambién es una opción, si está disponible.
Comodín el
Cabe señalar que zsh hace exactamente lo que solicitó el OP, siempre que la REMATCH_PCREopción esté configurada.
Tim Peoples
0

Se podría usar pcregrep. Viene con el paquete pcreen CentOS y pcregrepUbuntu.

grep -P podría tener este problema dependiendo del sistema operativo / versión:

-P, --perl-regexp
              Interpret PATTERN as a Perl regular expression.  This is highly experimental and grep -P may warn of unimplemented features.
sitio80443
fuente