Expressão regular entre aspas simples - perdem seu valor? [fechadas]

0

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

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

   howmany=$1

   shift
   ....
   ....
   etc

This uses the grep search utility to test if $1 matches the appropriate pattern. To do this we provide the regular expression ^-[0-9][0-9]*$ to grep, which is interpreted as "an initial dash followed by a digit, optionally followed by one or more digits." If a match is found then grep will return the match and the test will be true, otherwise grep will return nothing and processing will pass to the elif test.

Notice that we have enclosed the regular expression in single quotes to stop the shell from interpreting the $ and *, and pass them through to grep unmodified.

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

Obrigado pela sua ajuda.

    
por MathMan 27.10.2016 / 13:45

4 respostas

2

As aspas simples informam ao shell para manter os caracteres incluídos como estão, sem qualquer interpretação . A string entre aspas é passada como é para grep , sem as aspas: quando grep procura seus argumentos, ele vê

grep

e

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

e age sobre isso. (Leia Como os programas são executados se você estiver curioso sobre a construção de argumentos no Linux.)

bash e grep são diferentes. A maneira como esse comando usa aspas garante que bash não processe a string, mas grep faz.

    
por 27.10.2016 / 13:58
3

Enquanto outros responderam sua pergunta específica, acrescentarei que

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

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

  1. Você não pode usar echo para dados arbitrários
  2. Deixar uma expansão de parâmetro sem aspas como essa $1 acima é o operador split + glob.
  3. grep não combina o regex com sua entrada completa, mas em cada linha de entrada. Então, ele retornaria verdadeiro em foo\n-0\nbar , por exemplo.
  4. Um regexp pode corresponder ao comprimento zero, portanto, é errado, no caso geral, verificar se grep produz alguma saída (note que a substituição de comando remove caracteres de nova linha). É melhor usar grep -q e confiar no status de saída de grep , em vez de no [ , e também evitar a substituição de comando.
  5. Observe que o comando grep pode ser simplificado para grep -xE '-[0-9]+'

bash , ksh93 e zsh têm um operador dedicado para correspondência estendida de regexp. Para usá-lo de maneira portável e confiável em todos os três (e bash-3.1), a sintaxe é:

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

yash e zsh também suportam:

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

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

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

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

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

Em suma, é melhor usar awk , que é outra maneira padrão / portátil de fazer isso (observe que awk usa 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 alcançá-lo com uma construção padrão case :

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

Para usar grep , você poderia usá-lo com a opção --null (onde não há suporte como opção padrão) para que ele trabalhe em registros delimitados por NUL em vez de registros delimitados por nova linha. Como na maioria dos shells, $1 não pode conter NULs, isso deve ser seguro:

 if printf %s "$1" | grep --null -xq '-[0-9]+$'; then
   echo match
 fi
    
por 27.10.2016 / 14:27
1

As aspas simples evitam globbing (deixar bash interpretar curingas como * ) e a 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 grep os vê, ele é construído para entender a expressão regular, então então o regexp é interpretado dentro de grep .

Versão mais curta: argumentos de cotação única fornecem um meio de escapar do processamento do seu shell antes que o argumento seja passado para o comando.

    
por 27.10.2016 / 13:58
-2

Ele perde seu significado. grep usa quase os mesmos padrões de regex que o bash.

    
por 27.10.2016 / 13:48