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 colchete único:
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 "${var}"
para evitar problemas causados por espaços?
Respostas:
O colchete único
[
é na verdade um alias para otest
comando, não é uma sintaxe.Uma das desvantagens (de muitas) do colchete único é que, se um ou mais operandos que ele está tentando avaliar retornar uma sequência vazia, ele reclamará que esperava dois operandos (binários). É por isso que você vê as pessoas
[ x$foo = x$blah ]
, asx
garantias de que o operando nunca será avaliado como uma sequência vazia.O colchete duplo
[[ ]]
, por outro lado, é sintaxe e é muito mais capaz que[ ]
. Como você descobriu, ele não possui o único problema de operando e também permite uma sintaxe semelhante a C com os>, <, >=, <=, !=, ==, &&, ||
operadores.Minha recomendação é a seguinte: Se o seu intérprete for
#!/bin/bash
, use sempre[[ ]]
É importante observar que isso
[[ ]]
não é suportado por todos os shells POSIX, no entanto, muitos shells o suportam, comozsh
eksh
além debash
fonte
$foo
é!
ou(
ou-n
... Esse problema não deve ser um problema com shells POSIX, em que o número de argumentos (ao lado de[
e]
) não é maior que quatro.[ x$foo = x$blah ]
é tão errado quanto[ $foo = $bar ]
.[ "$foo" = "$bar" ]
está correto em qualquer shell compatível com POSIX,[ "x$foo" = "x$bar" ]
iria trabalhar em qualquer shell Bourne-like, mas ox
não é para casos onde você tem strings vazias mas onde$foo
podem estar!
ou-n
...[
não é exatamente um apelido paratest
. Se fosse,test
aceitaria um colchete de fechamento.test -n foo ]
. Mastest
não, e[
requer um.[
é idênticotest
em todos os outros aspectos, mas não é assim quealias
funciona. O Bash descreve[
etest
como componentes internos do shell , mas[[
como uma palavra-chave do shell .>=
e<=
O
[
comando é um comando comum. Embora a maioria dos shells o forneça como um built-in de eficiência, ela obedece às regras sintáticas normais do shell.[
é exatamente equivalente atest
, exceto que[
requer a]
como seu último argumento etest
não.Os colchetes duplos
[[ … ]]
são sintaxe especial. Eles foram introduzidos no ksh (vários anos depois[
) porque[
podem ser problemáticos de usar corretamente e[[
permitem algumas novas adições interessantes que usam caracteres especiais do shell. Por exemplo, você pode escreverporque toda a expressão condicional é analisada pelo shell, enquanto
[ $x = foo && $y = bar ]
que primeiro seria dividida em dois comandos[ $x = foo
e$y = bar ]
separada pelo&&
operador. Da mesma forma, colchetes duplos permitem coisas como a sintaxe de correspondência de padrões, por exemplo,[[ $x == a* ]]
para testar se o valor dex
começa coma
; entre colchetes, isso seria expandidoa*
para a lista de arquivos cujos nomes começama
no diretório atual. Os colchetes duplos foram introduzidos pela primeira vez no ksh e só estão disponíveis no ksh, bash e zsh.Dentro de colchetes, você precisa usar aspas duplas em torno de substituições de variáveis, como na maioria dos outros lugares, porque são apenas argumentos para um comando (que por acaso é o
[
comando). Dentro de colchetes duplos, você não precisa de aspas duplas, porque o shell não divide ou brilha palavras: está analisando uma expressão condicional, não um comando.Uma exceção, porém, é
[[ $var1 = "$var2" ]]
onde você precisa das aspas, se desejar fazer uma comparação de cadeias de bytes a bytes, caso contrário,$var2
seria um padrão com o qual comparar$var1
.Uma coisa que você não pode fazer
[[ … ]]
é usar uma variável como operador. Por exemplo, isso é perfeitamente legal (mas raramente útil):No seu exemplo
o comando dentro do
if
é[
com os 4 argumentos-d
,/home/mazimi/VirtualBox
,VMs
e]
. O shell analisa-d /home/mazimi/VirtualBox
e depois não sabe o que fazerVMs
. Você precisaria impedir a divisão de palavras${dir}
para obter um comando bem formado.De um modo geral, sempre use aspas duplas em torno de substituições de variáveis e comandos, a menos que você saiba que deseja executar a divisão e a observação de palavras no resultado. Os principais locais onde é seguro não usar aspas duplas são:
foo=$bar
(mas observe que você precisa de aspas duplas emexport "foo=$bar"
ou em atribuições de matriz comoarray=("$a" "$b")
);case
declaraçãocase $foo in …
:;=
ou==
operador (a menos que você deseja fazer a correspondência de padrões):[[ $x = "$y" ]]
.Em tudo isso, é correto usar aspas duplas, assim você pode pular as regras avançadas e usá-las o tempo todo.
fonte
[
é de fato do Sistema III em 1981 , pensei que era mais antigo.Implícito nesta pergunta é
${variable_name}
não significa o que você pensa que faz ...... se você acha que isso tem algo a ver com problemas causados por espaços (em valores variáveis). é bom para isso:
${variable_name}
e nada mais! 1 não faz qualquer bom a menos que você está seguindo-o imediatamente com um personagem que poderia ser parte de um nome de variável: uma carta (-ou-), um sublinhado (), ou um dígito (-). E mesmo assim, você pode contornar isso:
${variable_name}
A
Z
a
z
_
0
9
Não estou tentando desencorajar seu uso -
echo "${bar}d"
provavelmente é a melhor solução aqui -, mas desencorajar as pessoas a confiarem em aparelhos em vez de aspas, ou a aplicar aparelhos instintivamente e depois perguntarem: “Agora, também preciso de aspas ? ” Você deve sempre usar aspas menos que você tenha uma boa razão para não, e você tem certeza de que sabe o que está fazendo._________________
1 Exceto, é claro, o fato de que as formas mais sofisticadas de expansão de parâmetros , por exemplo, e se baseiam na sintaxe. Além disso, você precisa usar , etc. para referenciar os parâmetros 10, 11, etc., posicionais - as aspas não o ajudarão nisso.
${parameter:-[word]}
${parameter%[word]}
${parameter}
${10}
${11}
fonte
Para manipular espaços e caracteres especiais em branco nas variáveis, você deve sempre colocá-los entre aspas duplas. Definir um IFS adequado também é uma boa prática.
Recomendado: http://www.dwheeler.com/essays/filenames-in-shell.html
fonte