Expressão regular entre aspas simples - perde seu valor?

Expressão regular entre aspas simples - perde seu valor?

O livro que estou lendo - Learning the Bash Shell de O'Reilly especifica alguns códigos da seguinte forma:

if [ -n "$(echo $1 | grep '^-[0-9][0-9]*$')" ]; then 

   howmany=$1

   shift
   ....
   ....
   etc

Isso usa o greputilitário de pesquisa para testar se $1corresponde ao padrão apropriado. Para fazer isso, fornecemos a expressão regular ^-[0-9][0-9]*$ao grep, que é interpretada como "um travessão inicial seguido por um dígito, opcionalmente seguido por um ou mais dígitos". Se uma correspondência for encontrada, grepa correspondência será retornada e o teste será verdadeiro; caso contrário, grepnão retornará nada e o processamento passará para o elifteste.

Observe que colocamos a expressão regular entre aspas simples para impedir que o shell interprete $ e * e os transmita para grep sem modificação.

Então, por que a expressão regular não '^-[0-9]'perde seu significado como entre aspas simples, geralmente tudo entre aspas simples perde seu significado.

Obrigado pela ajuda.

Responder1

Embora outros tenham respondido à sua pergunta específica, acrescentarei que

if [ -n "$(echo $1 | grep '^-[0-9][0-9]*$')" ]; then 

É uma maneira errada de verificar se uma string corresponde a uma expressão regular por vários motivos:

  1. Você não pode usar echopara dados arbitrários
  2. Deixar uma expansão de parâmetro sem aspas como $1acima é o operador split+glob.
  3. grepnão corresponde ao regex com sua entrada completa, mas em cada linha de sua entrada. Portanto, retornaria verdadeiro, foo\n-0\nbarpor exemplo.
  4. Um regexp pode corresponder a comprimento zero, portanto, no caso geral, é errado verificar se grepproduz alguma saída (observe que a substituição do comando tira os caracteres de nova linha à direita). É melhor usar grep -qe confiar no status de saída de grep, em vez de [, e também evitar a substituição de comando.
  5. Observe que esse grepcomando pode ser simplificado paragrep -xE '-[0-9]+'

bashe ksh93tem zshum operador dedicado para correspondência de regexp (estendida). Para usá-lo de forma portável e confiável em todos os três (e no bash-3.1), a sintaxe é:

re='^-[0-9]+$'
if [[ $1 =~ $re ]]; then
  echo matches
fi

yashe zshtambém suporte:

if [ "$1" '=~' '^-[0-9]+$' ]; then
  echo matches
fi

O comando padrão para fazer a correspondência de regex de string (básica) é expr:

if expr " $1" : ' -[0-9]\{1,\}$' > /dev/null; then
  echo matches
fi

Observe que o ^(mas não $) está implícito em expr. Também usamos esse caractere de espaço inicial para evitar problemas com valores que $1sejam exproperadores.

Observe também que se a regex contiver \(...\), isso afetará o comportamento de expr.

Resumindo, é melhor usar, awkque é outra maneira padrão/portátil de fazer isso (observe que awkusa regexps estendidos):

if STRING=$1 RE='^-[0-9]+$' awk '
  BEGIN{exit(ENVIRON["STRING"] !~ ENVIRON["RE"])}'; then
...

Ou use uma função:

re_match() {
  STRING=$1 RE=$2 awk '
    BEGIN{exit(ENVIRON["STRING"] !~ ENVIRON["RE"])}'
}

if re_match "$1" '^-[0-9]+$'

Nesse caso, você também pode conseguir isso com uma caseconstrução padrão:

case $1 in
  ("" | *[!0-9-]* | [!-]* | - | ?*-*) ;;
  (*) echo match;;
esac

Para usar grep, você pode usá-lo com a --nullopção (quando compatível, pois não é uma opção padrão) para fazê-lo funcionar em registros delimitados por NUL em vez de registros delimitados por nova linha. Como na maioria dos shells $1não pode conter NULs, isso deve ser seguro:

 if printf %s "$1" | grep --null -xq '-[0-9]+$'; then
   echo match
 fi

Responder2

Aspas simples dizem ao shell para manter os caracteres incluídos como estão,sem qualquer interpretação. A string citada é passada como está para grep, sem as aspas: quando grepprocura seus argumentos, ela vê

grep

e

^-[0-9][0-9]*$

e age sobre isso. (LerComo os programas são executadosse você estiver curioso sobre a construção de argumentos no Linux.)

bashe grepsão diferentes. A forma como este comando usa aspas garante que bashnão processe a string, mas grepsim.

Responder3

Aspas simples evitamglobulando(permitindo bashinterpretar curingas como *) e expansão de variáveis ​​através do uso de $. Basicamente, você está dizendo para bash"pegar literalmente esses caracteres e passá-los para grep". Quando grepos vê, ele é construído para entender expressões regulares, entãoentãoo regexp é interpretado dentro grep.

Versão mais curta: argumentos com aspas simples fornecem um meio de escapar do processamento do seu shell antes que o argumento seja passado para o comando.

Responder4

Perde o sentido. grepusa quase os mesmos padrões de regex do bash.

informação relacionada