Por que usar aspas duplas em um teste [[]]?

23

Digamos que temos 2 números inteiros em um script bash:

value1=5
value2=3

Então, por que precisamos usar aspas duplas no caso de um teste? Por exemplo:

if [[ "$value1" -eq "$value2" ]]

Por que não usar apenas o seguinte?

if [[ $value1 -eq $value2 ]]

Para mim, as aspas duplas não fazem sentido.

Meerkat
fonte
5
Citando na casca tem pouco a ver com cordas É realmente sobre a prevenção da shell de executar divisão palavra (como em tipos de dados.) (E outros tipos de expansões.)
filbranden
13
Embora, como Terdon apontou, não seja necessário também citar variáveis ​​nesse construto específico (e, é claro, com valores de uma palavra em qualquer lugar), eu gostaria de dar conselhos para sempre citar seus vars. Você realmente sabe em quais contextos você pode deixar variáveis ​​sem aspas? O motivo para citar, mesmo que não seja necessário com 5e 3, é a manutenção. Os valores podem mudar mais tarde e os erros resultantes podem não ser óbvios.
Peter - Restabelecer Monica
2
@sudodus Eu não acho que isso seja verdade [[ ]], apenas para [ ].
Benjamin W.
1
Você está certo, @BenjaminW. A divisão de palavras não é o único caso pelo qual é uma boa ideia usar aspas duplas para variáveis. Também existe o caso em que uma variável está em branco. Isso fará com que a declaração em [] falhe (por exemplo, [2-eq] com um erro, mas [[]] não seja vulnerável (como no caso da divisão de palavras).)
sudodus 15/02
2
@marcelm, Bash, ksh e Zsh têm variáveis ​​inteiras e, dentro delas, também coagem [[ ]]os operandos -eqa inteiros.
ilkkachu 15/02

Respostas:

7

Divisão de palavras.

Este exemplo é muito improvável, mas possível ; portanto, se você quiser codificar defensivamente, cubra suas faixas com aspas:

$ set -x
$ value1=5
+ value1=5
$ value2=3
+ value2=3
$ [ $value1 -eq $value2 ]
+ '[' 5 -eq 3 ']'

Tudo bem, até agora. Vamos jogar a chave na engrenagem:

$ IFS=456
+ IFS=456
$ [ $value1 -eq $value2 ]
+ '[' '' -eq 3 ']'
bash: [: : integer expression expected

Opa

$ [ "$value1" -eq "$value2" ]
+ '[' 5 -eq 3 ']'

Ahh

Glenn Jackman
fonte
2
Como o OP usa colchetes duplos, não ocorre divisão de palavras.
user000001 15/02
5
Sim, isso não é realmente relevante para a [[ ]]construção do bash .
terdon
1
Eh? [ $value1 -eq $value2 ]com um vazio value1seria '[' -eq 3 ']'sem ''no lado esquerdo.
Charles Duffy
Fiquei surpreso também, mas há evidências.
glenn jackman
1
Esta resposta não está diretamente relacionada à pergunta. Estou surpreso que tenha sido aceito. Definindo como wiki da comunidade.
glenn jackman 20/02
35

Você realmente não precisa das aspas aqui. Este é um dos poucos casos em que é seguro usar uma variável sem aspas. Você pode confirmar isso com set -x:

$ var1=""
$ var2="3"
$ set -x
$ if [[ $var1 -eq $var2 ]]; then echo "match!"; else echo "no match!"; fi
+ [[ '' -eq 3 ]]
+ echo 'no match!'
no match!
$ if [[ "$var1" -eq "$var2" ]]; then echo "match!"; else echo "no match!"; fi
+ [[ '' -eq 3 ]]
+ echo 'no match!'
no match!

Como você pode ver acima, as versões citadas e não citadas do teste são resolvidas exatamente da mesma maneira pelo bash. O mesmo deve ser verdade para zshe, eu acho, para qualquer outro shell que suporte o [[ ]]operador.

Observe que este não é o caso dos mais portáteis [ ]:

$ if [ $var1 -eq $var2 ]; then echo "match!"; else echo "no match!"; fi
+ '[' -eq 3 ']'
sh: [: -eq: unary operator expected
+ echo 'no match!'
no match!

A [ ]construção, diferentemente da construção, [[ ]]requer citação.


Alguns links úteis para saber mais sobre quando e por que a citação é necessária:

terdon
fonte
Nesse caso, com variáveis ​​inteiras, seria melhor declará-las como tal. declare -i var1=é 0quando avaliado.
Freddy
4
Observe que -eqé uma comparação aritmética , para que você possa deixar de $fora (dentro [[ .. ]]) e escrever [[ a -eq b ]]. Com a comparação de strings, você precisa $, é claro, de[[ $a = $b ]]
ilkkachu
2
@ user000001 bom ponto. Embora, é claro, seja muito possível que você queira que eles sejam expandidos. Por exemplo, seria de esperar que este seja um jogo: var1="afoob"; var2="a*b"; [[ $var1 = $var2 ]] && echo match. Se você deseja usar os caracteres glob sem que eles atuem como glob em um contexto brilhante (como o [[ ]]), é necessário citar sim.
terdon
3
@ilkkachu, isso me surpreende. Eu pensei que variáveis ​​"simples" seriam consideradas apenas dentro de um array subscrito ou ((...))ou $((...). Parece funcionar, mas (velho rabugento, ative) eu não gosto.
glenn jackman
1
@glennjackman, desculpe-me por lhe dizer isso, mas sim, os operandos -eqe amigos internos também [[ ]]são contextos aritméticos. :) (Relacionado: Expansão automática de variáveis ​​dentro do comando bash [[]] )
ilkkachu 15/02
17

Mesmo que as aspas duplas não sejam necessárias, os motivos para usá-las são:

  • Boas práticas / hábito: nesse caso, elas não são necessárias, mas, em geral, aspas duplas são para evitar a divisão não intencional de palavras.
  • Porque value1e value2são variáveis, e você pode não saber o que elas contêm. Caso contrário, você pode muito bem perguntar: "Por que se preocupar com as variáveis em vez de verificar if [[ 5 -eq 3 ]]? Ou levá-lo ainda mais, por que se preocupar com o ifem tudo quando você já sabe que 5 não é igual a 3? Muitas vezes é melhor ficar na defensiva. (É verdade essa divisão de palavras não ocorrerá [[, mas os casos em que a divisão de palavras não ocorre são raros. Novamente, veja o primeiro ponto.)
jamesdlin
fonte
1

Não está diretamente relacionado à sua pergunta, mas eu uso

if (($ value1 == $ value2)); então

quando eu comparo números, mas você também não precisa usar aspas.

framp
fonte
2
if (( value1 == value2 )); then. Em contextos aritméticos, você nem precisa do $. Essa questão, no entanto, parece focar nas variáveis ​​usadas nos [[ ... ]]testes.
Kusalananda
1
Eu sei. Mas, francamente, não uso esse recurso porque quero que meus nomes de variáveis ​​sejam consistentes e, portanto, use $ como prefixo o tempo todo.
framp
1

Você está absolutamente certo!

A citação entre colchetes duplos não faz sentido, pelo menos nesse caso.

Mas como eu uso aspas duplas diariamente - especialmente para expressões com colchetes simples, passando argumentos para funções e scripts, além de atribuições de variáveis ​​às vezes (o que é completamente inútil para delcarações simples) - acho que algumas pessoas, pelo menos, escreva aspas duplas em torno de expansões variáveis ​​instintivamente .

As aspas duplas podem dar uma sensação de segurança. É como voltar para casa, onde estão aspas duplas. - D. Kummer

Um benefício de fazer aspas duplas de forma consequente e compreensível - mas apenas como faz sentido - é que os colegas de trabalho que são novos no bash podem aprender a escrever scripts mais estáveis . Isso também acentua o fato de que a arte do processamento de dados com o bash é mais sobre a separação de fluxos de dados (incluindo variáveis) por separadores de campo e os canaliza através de filtros . Assim que seus blocos de dados estiverem separados do fluxo, mantenha-os juntos com aspas duplas!

Outro benefício poderia ser a melhor legibilidade de scripts bash com seqüências de caracteres entre aspas duplas dentro de um editor de realce de código .

Dominik Kummer
fonte