O Bash aceita ambas as sintaxes:
FOO=$(($BAR + 42))
e
FOO=$((BAR + 42))
Qual é o correto / mais portátil / menos propenso a erros? Ou ambos são igualmente válidos?
O Bash aceita ambas as sintaxes:
FOO=$(($BAR + 42))
e
FOO=$((BAR + 42))
Qual é o correto / mais portátil / menos propenso a erros? Ou ambos são igualmente válidos?
Depende do que você quer fazer, mas você deve validar todas as entradas usadas no contexto aritmético primeiro (veja o final).
Expansões de parâmetros como
$var
substituições de comandos são feitas antes que a expressão aritmética em si seja analisada. (*) Essa expansão acontece sem levar em conta a sintaxe aritmética, então$var
você pode mexer nisso.Por outro lado, sem o
$
sinal,var
é avaliado após a expressão aritmética ser analisada, e deve ser algo que avalie um valor. Pode ser uma expressão completa no Bash (**) .(* exceto que alguns shells fazem exceções para que algo como
$(( a[$key] = 1 ))
funcione mesmo quekey
seja]
.)(** A maioria dos outros shells também permite expressões completas em variáveis, mas não, por exemplo, Dash, no
/bin/sh
Debian e Ubuntu.)Portanto, por exemplo, usar
$var
pode produzir um erro de sintaxe se a variável estiver vazia, enquanto comvar
será tratado como zero.10 - $var
produz apenas10 -
, uma expressão inválida. (Isso não acontece no seu exemplo de$BAR + 42
porque+ 42
é uma expressão válida.)Por outro lado, você pode
$var
incluir expressões parciais:Com
var
, você só pode incluir subexpressões completas (em Bash):mas observe que usar
$var
aqui mudaria a ordem de avaliação!Aqui, a variável é primeiro expandida, resultando em
10 * 1+2
, que é então analisado usando as regras aritméticas normais, multiplicando primeiro, sendo o mesmo que(10 * 1) + 2
.$(( 10 * var ))
sem o cifrão efetivamente coloca parênteses implícitos ao redor da variável, então é um pouco como$(( 10 * (1+2) ))
.Como parte da interpretação de variáveis como expressões completas, o Bash seguirá a cadeia de nomes se uma variável nomear outra:
A forma sem o cifrão só funciona para variáveis nomeadas reais. Se você quiser usar os parâmetros posicionais
$1
,$2
... ou variáveis especiais como$#
ou$?
em aritmética, você terá que usar a forma cifrão. (O que deve ser bem óbvio, mas ainda assim.)Veja também Bash: expansão aritmética, expansão de parâmetros e o operador vírgula para outra diferença interessante.
Embora você deva citar expansões como de costume , você não precisa citar expansões de variáveis dentro da expressão aritmética, e fazer isso quebraria muitos shells. Então, use
"$(( ...))"
, mas não$(( "$foo" ))
(por exemplo, zsh croaks emi=123; echo $(( "$i" ))
)Independentemente de tudo isso , observe que a avaliação aritmética do Bash é vulnerável a injeções de comando triviais em ambos os casos, como:
Isso significa que se você obtiver valores de fora, você deve validá-los primeiro, antes de usá-los em um contexto aritmético. E se depois dessa validação você souber que tem um número simples, não importa qual forma você use.
(Isso não acontece no Dash, já que ele não suporta arrays, e o zsh parece não cair nessa.)