La expresión regular correcta no funciona en grep

13

Tengo esta expresión regular:

(?<=prefix).*$

que devuelve cualquier carácter que sigue al "prefijo" de la cadena y funciona bien en cualquier motor de expresiones regulares en línea (por ejemplo, https://regex101.com ). El problema es cuando uso esa expresión regular en bash:

grep '(?<=prefix).*$' <<< prefixSTRING

No coincide con nada. ¿Por qué esa expresión regular no funciona con grep?

mark009
fuente
11
Esto realmente resalta por qué regex101 necesita un selector de sabor POSIX como lo hace para JS, Perl / PHP y Python. No puedo contar la cantidad de veces que he deseado eso.
Jared Smith
Además, .*$coincide con cualquier cadena hasta el final de la línea (o el final de la cadena), no cualquier carácter.
ilkkachu

Respuestas:

38

Parece que ha definido la expresión regular correcta, pero no ha establecido las marcas suficientes en la línea de comandos para grepcomprenderla. Porque por defecto grepsoporta BRE y con -Eflag lo hace ERE. Lo que tiene (look-aheads) está disponible solo en el sabor de expresión regular PCRE, que solo se admite en GNU grepcon su -Pbandera.

Suponiendo que necesita extraer solo la cadena coincidente después prefixde agregar un indicador adicional -opara saber grepque imprime solo la parte correspondiente como

grep -oP '(?<=prefix).*$' <<< prefixSTRING

También hay una versión grepque admite bibliotecas PCRE de forma predeterminada, pcregrepen la que simplemente puede hacer

pcregrep -o '(?<=prefix).*$' <<< prefixSTRING

La explicación detallada de varios sabores de expresiones regulares se explica en la maravillosa respuesta de Giles y las herramientas que implementan cada uno de ellos.

Inian
fuente
38

Las expresiones regulares vienen en muchos sabores diferentes. Lo que está mostrando es una expresión regular similar a Perl (PCRE, "Expresión regular compatible con Perl").

grephace POSIX expresiones regulares. Estas son expresiones regulares básicas (BRE) y expresiones regulares extendidas (ERE, si grepse usa con la -Eopción). Consulte el manual re_formato el regexo lo que sea semejante manual del grepmanual se refiere a en su sistema, o los textos estándar POSIX que acabo de dichos enlaces.

Si usa GNU grep, podría usar expresiones regulares similares a Perl si usara grepla opción grepespecífica de GNU -P.

También tenga en cuenta que grepdevuelve líneas por defecto, no subcadenas de líneas. Nuevamente, con GNU grep(y algunas otras grepimplementaciones), puede usar la -oopción para obtener solo los bits que coinciden con la expresión dada de cada línea.

Tenga en cuenta que ambas -Py -ono son extensiones estándar de la especificación POSIXgrep .

Si no está utilizando GNU grep, puede utilizarlo sedpara obtener el bit entre la cadena prefixy el final de la línea:

sed -n 's/.*prefix\(.*\)/\1/p' file

Lo que esto hace es imprimir solo las líneas que sedlogran aplicar la sustitución dada. La sustitución reemplazará toda la línea que coincide con la expresión (que es un BRE), con el fragmento que aparece después de la cadena prefix.

Tenga en cuenta que si hay varias instancias prefixen una línea, la sedvariación devolvería la cadena después de la última , mientras que la grepvariación GNU devolvería la cadena después de la primera (que incluiría las otras instancias de prefix).

La sedsolución sería portátil para todos los sistemas tipo Unix.

Kusalananda
fuente
6

Como han dicho las otras respuestas, grepno utiliza un sabor regex con lookbehinds (por defecto con GNU grep, o no con otras versiones).

Si no puede usar GNU grepo pcregrep, puede usarlo perlsi lo tiene.

La línea de comando equivalente con perlsería:

perl -ne 'print if /(?<=prefix).*$/' <<< prefixSTRING

Pones la expresión regular deseada entre las barras. Como está usando Perl, esto usa el sabor de expresión regular de Perl .

cuántico
fuente
o print "$&\n" if ...si quieren emitir solo la parte posterior a laprefix
ilkkachu