Por que a expansão de parâmetro com espaços sem aspas funciona dentro de colchetes duplos “[[” mas não entre colchetes únicos “[”?

79

Estou confuso com o uso de colchetes simples ou duplos. Veja este código:

dir="/home/mazimi/VirtualBox VMs"

if [[ -d ${dir} ]]; then
    echo "yep"
fi

Funciona perfeitamente, embora a string contenha um espaço. Mas quando eu mudo para um único colchete:

dir="/home/mazimi/VirtualBox VMs"

if [ -d ${dir} ]; then
    echo "yep"
fi

Diz:

./script.sh: line 5: [: /home/mazimi/VirtualBox: binary operator expected

Quando eu mudo para:

dir="/home/mazimi/VirtualBox VMs"

if [ -d "${dir}" ]; then
    echo "yep"
fi

Funciona bem. Alguém pode explicar o que está acontecendo? Quando devo atribuir aspas duplas em torno de variáveis como "${var}" para evitar problemas causados por espaços?

    
por Majid Azimi 20.02.2012 / 19:37

4 respostas

80

O único colchete [ é na verdade um alias para o comando test , não é a sintaxe.

Uma das desvantagens (de muitas) do único colchete é que se um ou mais dos operandos que ele está tentando avaliar retornar uma cadeia vazia, ele irá reclamar que estava esperando dois operandos (binário). É por isso que você vê as pessoas fazendo [ x$foo = x$blah ] , o x garante que o operando nunca irá avaliar uma string vazia.

O colchete duplo [[ ]] , por outro lado, é sintaxe e é muito mais capaz do que [ ] . Como você descobriu, ele não tem o problema do operando único e também permite uma sintaxe semelhante a C com operadores >, <, >=, <=, !=, ==, &&, || .

Minha recomendação é a seguinte: Se o seu intérprete for #!/bin/bash , sempre usará [[ ]]

É importante observar que [[ ]] não é suportado por todos os shells POSIX, no entanto, muitos shells suportam, como zsh e ksh , além de bash

    
por 20.02.2012 / 19:42
48

O comando [ é um comando comum. Embora a maioria das shells a forneça como um built-in para eficiência, ela obedece às regras sintáticas normais da shell. [ é exatamente equivalente a test , exceto que [ requer um ] como seu último argumento e test não.

Os colchetes duplos [[ … ]] são sintaxe especial. Eles foram introduzidos em ksh (vários anos depois de [ ) porque [ pode ser problemático para usar corretamente e [[ permite algumas novas adições que usam caracteres especiais do shell. Por exemplo, você pode escrever

[[ $x = foo && $y = bar ]]

porque toda a expressão condicional é analisada pelo shell, enquanto [ $x = foo && $y = bar ] primeiro seria dividido em dois comandos [ $x = foo e $y = bar ] separados pelo operador && . Similarmente, colchetes duplos permitem coisas como a sintaxe de correspondência de padrões, por exemplo, [[ $x == a* ]] para testar se o valor de x começa com a ; em colchetes, isso expandiria a* para a lista de arquivos cujos nomes começam com a no diretório atual. Os colchetes duplos foram introduzidos pela primeira vez em ksh e estão disponíveis apenas em ksh, bash e zsh.

Dentro de colchetes únicos, você precisa usar aspas duplas em torno das substituições de variáveis, como na maioria dos outros lugares, porque elas são apenas argumentos para um comando (que é o comando [ ). Dentro de colchetes duplos, você não precisa de aspas duplas, porque o shell não faz divisão de palavras ou globbing: está analisando uma expressão condicional, não um comando.

Uma exceção é [[ $var1 = "$var2" ]] , em que você precisa das aspas se quiser fazer uma comparação de cadeia de byte a byte, caso contrário, $var2 seria um padrão para corresponder a $var1 contra.

Uma coisa que você não pode fazer com [[ … ]] é usar uma variável como operador. Por exemplo, isso é perfeitamente legal (mas raramente é útil):

if [ -n "$reverse_sort" ]; then op=-gt; else op=-lt; fi
…
if [ "$x" "$op" "$y" ]; then …

No seu exemplo

dir="/home/mazimi/VirtualBox VMs"
if [ -d ${dir} ]; then …

o comando dentro de if é [ com os 4 argumentos -d , /home/mazimi/VirtualBox , VMs e ] . O shell analisa -d /home/mazimi/VirtualBox e, em seguida, não sabe o que fazer com VMs . Você precisaria evitar que a divisão de palavras em ${dir} obtenha um comando bem formado.

De um modo geral, use sempre aspas duplas em torno das substituições de variáveis e comandos, a menos que você saiba que deseja executar a divisão de palavras e globbing no resultado. Os principais lugares onde é seguro não usar as aspas duplas são:

  • em uma atribuição: foo=$bar (mas observe que você precisa das aspas duplas em export "foo=$bar" ou em atribuições de matriz como array=("$a" "$b") );
  • em uma instrução case : case $foo in … ;
  • entre colchetes duplos, exceto no lado direito do operador = ou == (a menos que você queira correspondência de padrões): [[ $x = "$y" ]] .

Em todos eles, é correto usar aspas duplas, então você pode ignorar as regras avançadas e usar as aspas o tempo todo.

    
por 21.02.2012 / 01:58
8

When should I assign double quotes around variables like "${var}" to prevent problems caused by spaces?

Implícito nesta questão é

Why isn’t ${variable_name} good enough?

${variable_name} não significa o que você acha que faz…

... se você acha que tem qualquer coisa para fazer com problemas causados por espaços (em valores variáveis). ${variable_name} é bom para isso:

$ bar=foo
$ bard=Shakespeare
$ echo $bard
Shakespeare
$ echo ${bar}d
food

e nada mais! 1 ${variable_name} não faz qualquer bom a menos que você esteja seguindo-o imediatamente com um personagem que poderia fazer parte de um nome de variável: uma letra ( A - Z ou a - z ), um sublinhado ( _ ) ou um dígito ( 0 - 9 ). E mesmo assim, você pode contornar isso:

$ echo "$bar"d
food

Não estou tentando desencorajar seu uso - echo "${bar}d" é provavelmente a melhor solução aqui - mas para desencorajar as pessoas de confiar em chaves em vez de , ou aplicar suspensórios instintivamente e depois perguntar: "Agora, eu preciso de citações, também? " Você deve sempre usar aspas, a menos que tenha uma boa razão para não e você tem certeza de que sabe o que está fazendo.

por 30.05.2016 / 21:22
2

Para manipular espaços e caracteres | especiais em branco em variáveis, você deve sempre colocá-los entre aspas duplas. Definir um IFS adequado também é uma boa prática.

Recomendado: link

    
por 20.02.2012 / 19:48