¿El resultado de grep regex no es el esperado?

¿El resultado de grep regex no es el esperado?

Usando FreeBSD 11.1:

#!/bin/sh

if printf 'abcde.fgh' | grep -iEq '^[^][$^*_-]'; then
    echo "test 1 success"
else
    echo "test 1 fail"
fi

echo

if printf 'abcde.fgh' | grep -iEq '^[^][.$^*_-]'; then
    echo "test 2 success"
else
    echo "test 2 fail"
fi

Producción:

test 1 success

grep: Unmatched [ or [^
test 2 fail

Pero AFAICT estos deberían dar el mismo resultado. Ambos contienen una condición en el primer carácter (únicamente), que no forma parte de una lista de caracteres no alfabéticos especificados. Desglose de la expresión regular:

  • ^= inicio de la cadena
  • [^...]= coincide si ninguno de estos caracteres
  • Dentro de la lista, ]debe ser el primer carácter, ^no debe ser el primero y debe ser el último. También lo ][.^$_-es una lista válida de caracteres literales y la cadena no debe coincidir con ninguno de ellos.
  • Para evitar confusiones, tenga en cuenta que esto significa que ][hay literales "]"y "["caracteres en la lista,noun cierre y reapertura de 2 listas.

La única diferencia entre las 2 expresiones es que "."está dentro de una lista, por lo que debe tratarse como tal not literal .y, de hecho, el primer carácter no coincide con el literal."."

¿Qué me estoy perdiendo? ¿Algo muy obvio y simple, probablemente?

Respuesta1

Le faltan algunas otras reglas de sintaxis. Dentro de una expansión de corchetes, además de los rangos simples, también hay algunos tipos de expresiones de varios caracteres que comienzan con [. (Ver elexpresión regular(7)manual paralinuxoFreeBSDen "Con excepción de estosy algunas combinaciones usando '['(ver párrafos siguientes)".) Estos son:

  • Elementos de cotejo: [..]
  • Clases de equivalencia: [==]
  • Clases de personajes: [::]

(Es posible que haya visto o usado expresiones como [[:digit:]]: estas son en realidad una clase de carácter [:digit:]que resulta ser el único elemento de una […]expansión de corchetes).

Entonces, en su caso, dado que .está inmediatamente después de [, se reconocen como el delimitador de apertura de un elemento de clasificación. GNU grep 3.1 tiene el mensaje de error correcto:

$ printf 'abcde.fgh' | grep -iEq '^[^][.$^*_-]'
grep: Unmatched [, [^, [:, [., or [=

Las mismas expresiones se pueden usar para escapar de tales situaciones usando, por ejemplo, [...]o [=.=]para incluir un punto normal, o de manera similar [=-=]para hacer coincidir un guión, si no hay ningún lugar donde moverlos.

información relacionada