O resultado da regex do Grep não é o esperado?

O resultado da regex do Grep não é o esperado?

Usando o 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

Saída:

test 1 success

grep: Unmatched [ or [^
test 2 fail

Mas AFAICT estes devem dar o mesmo resultado. Ambos contêm uma condição no primeiro caractere (apenas), de que não faz parte de uma lista de caracteres não alfabéticos especificados. Detalhamento do regex:

  • ^= início da string
  • [^...]= corresponde se nenhum desses caracteres
  • Dentro da lista, ]deve ser o primeiro caractere, ^não deve ser o primeiro e - deve ser o último. Portanto, ][.^$_-é uma lista válida de caracteres literais e a string não deve corresponder a nenhum deles.
  • Para evitar confusão, observe que isso significa que ][são literais "]"e "["caracteres na lista,nãoum fechamento e reabertura de 2 listas.

A única diferença entre as 2 expressões é que "."está dentro de uma lista, portanto deve ser tratada como not literal .e de fato o primeiro caractere não corresponde ao literal"."

o que estou perdendo? Algo muito óbvio e simples, provavelmente?

Responder1

Estão faltando algumas outras regras de sintaxe. Dentro de uma expansão de colchetes, além dos intervalos simples, também existem alguns tipos de expressões com vários caracteres que começam com [. (Veja oexpressão regular(7)manual paraLinuxouFreeBSDem "Com exceção destese algumas combinações usando '['(veja os próximos parágrafos)".) São eles:

  • Elementos de agrupamento: [..]
  • Classes de equivalência: [==]
  • Classes de personagens: [::]

(Você pode ter visto ou usado expressões como [[:digit:]]– estas são na verdade uma classe de caracteres [:digit:]que é o único elemento de uma […]expansão de colchetes.)

Portanto, no seu caso, como .acontece imediatamente após a [, eles são reconhecidos como o delimitador de abertura de um elemento de agrupamento. GNU grep 3.1 tem a mensagem de erro correta:

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

As mesmas expressões podem ser usadas para escapar de tais situações usando, por exemplo, [...]ou [=.=]para incluir um ponto regular, ou similarmente [=-=]para corresponder a um traço, se não houver para onde movê-los.

informação relacionada