Bash comportamento de expansão variável ao usar espaços simples ou duplos

4

Eu tive um problema em um script de backup bash causado pelo seguinte comportamento que não entendi.

Primeiro, criamos um parâmetro que contém uma string com dois espaços consecutivos (logo antes de "< '):

me@mysystem:~$ TEST="a string with 2 spaces right  <--HERE!"
me@mysystem:~$ echo $TEST
a string with 2 spaces right <--HERE!

Eu posso usar um espaço:

me@mysystem:~$ echo ${TEST} | grep " "
a string with 2 spaces right <--HERE!

Eu posso usar um espaço seguido por outra letra:

me@mysystem:~$ echo ${TEST} | grep " s"
a string with 2 spaces right <--HERE!

Eu posso grep a parte depois dos 2 espaços:

me@mysystem:~$ echo ${TEST} | grep "HERE"
a string with 2 spaces right <--HERE!

Eu posso fazer uma expansão variável substituindo os dois espaços por um sublinhado:

me@mysystem:~$ echo ${TEST// /_}
a_string_with_2_spaces_right__<--HERE!

Mas o espaço duplo requer a citação da variável:

me@mysystem:~$ echo $TEST   | grep "  "; echo "Done."
Done.
me@mysystem:~$ echo ${TEST} | grep "  "; echo "Done."
Done.
me@mysystem:~$ echo "$TEST" | grep "  "; echo "Done."
a string with 2 spaces right  <--HERE!
Done.
me@mysystem:~$ echo "${TEST}" | grep "  "; echo "Done."
a string with 2 spaces right  <--HERE!
Done.

Eu não entendo porque este é o caso.

Longa história curta: Eu tinha uma declaração if no script verificando se $ {FILE} representa um arquivo existente, e que aparentemente também pára de interpretar a variável quando encontra um espaço, a menos que seja citado. Então, eu não tenho mais certeza do que $ {} faz ou não toma cuidado.

É melhor sempre citar a variável, eu acho?

    
por Sam Van den Eynde 18.11.2016 / 21:00

1 resposta

5

Este é um caso clássico de divisão de palavras, feito por shell, em expansão de variável sem nome.

Basicamente, quando você faz, $TEST (sem aspas ( "$TEST" )), o shell:

  • Executa a divisão de palavras, com base no valor da variável de ambiente IFS (padrão: espaço, guia, nova linha) e divide a expansão inteira em palavras separadas

  • Assim como você tem dois espaços consecutivos, a divisão de palavras (e também a expansão pathname (glob) se houver * , ? , [] está presente) e quando a cadeia de saída é reconstruído as palavras são unidas pelo espaço, como resultado, você tem apenas um espaço entre right e <--HERE! . Isso seria verdadeiro para qualquer combinação de IFS caracteres.

Em suma, cite suas expansões variáveis:

"${variable}"
    
por heemayl 18.11.2016 / 21:10

Tags