$(cmd arg)é executado cmdem um ambiente de subshell e sua saída (menos os caracteres de nova linha à direita) torna-se o resultado da expansão.
(cmd arg)é executado em um subshell com sua saída não afetada.
Então $((cmd arg))seria o mesmo, $(cmd arg)mas com uma camada extra de subshell, exceto que não é.
$((...))é uma forma separada de expansão que vem do shell Korn. No shell Korn, ((arithmetic expression))avalia a expressão aritmética (que segue uma sintaxe muito semelhante à de C) e o status de saída reflete se a expressão resolve para 0 ou diferente de zero.
Isso permite coisas como:
if ((var < 10)); then
...
fi
O que o torna muito semelhante ao C.
$é usado para introduzir expansões . Assim como $(cmd)é como (cmd)exceto que se expande para a saída de cmd, $((arith))é como ((arith))exceto que se expande para o resultado da avaliação da expressão aritmética.
POSIX, cujo shé principalmente baseado em ksh88, especificado, $((...))mas não ((...)). Na verdade, em um rascunho anterior, estava indo para o $[...]lugar, e é por isso que você encontra isso bashe zshsuporta $[...]como uma alternativa ao $((...)).
IIRC, a principal razão pela qual o POSIX inicialmente pensou em especificá-lo como $[...]é porque $((...))entra em conflito com $((cmd arg)), um subshell dentro de uma substituição de comando.
Você verá que a maioria dos shells identifica corretamente $((echo x; echo y) | (tr xy ab))como não uma expansão aritmética, mas não $((cmd arg)). Em qualquer caso $((cmd)), pretende expandir para o valor aritmético da $cmdvariável, não para a saída de cmd.
O texto relevante na especificação POSIX tem:
A sintaxe da linguagem de comando do shell tem uma ambiguidade para expansões que começam com "$((", que pode introduzir uma expansão aritmética ou uma substituição de comando que começa com um subshell. A expansão aritmética tem precedência; isto é, o shell deve primeiro determinar se ele pode analisar a expansão como uma expansão aritmética e só deve analisar a expansão como uma substituição de comando se determinar que não pode analisar a expansão como uma expansão aritmética. O shell não precisa avaliar expansões aninhadas ao realizar essa determinação. Se encontrar o fim de entrada sem já ter determinado que não pode analisar a expansão como uma expansão aritmética, o shell deve tratar a expansão como uma expansão aritmética incompleta e relatar um erro de sintaxe.Um aplicativo em conformidade deve garantir que ele separe "$(" e '(' em dois tokens (ou seja, separe-os com espaço em branco) em uma substituição de comando que começa com um subshell. Por exemplo, uma substituição de comando contendo um único subshell poderia ser escrito como:
ksh's ((...))também entra em conflito com subshells aninhados. Embora o POSIX não especifique ((...)), ele permite o comportamento do ksh.
Na prática, ao aninhar subshells e/ou cmdsubsts, certifique-se de incluir espaço em branco entre os parênteses:
Aqui está uma demonstração de que não é executado em um subshell: você pode modificar variáveis em uma expressão aritmética:
$ x=5; echo "$(( x *= 2 ))"; echo "$x"
10
10
Se fosse um subshell, echo $xgeraria 5.
Ao usar a aritmética de shell, observe que nem todos os shells suportam pré e pós-incremento; dash(o padrão /bin/shnas versões atuais do Debian e derivados) irá interpretar $(( ++i ))como $(( +(+i) ))e NÃO incrementar a ivariável.
$(cmd arg)
é executadocmd
em um ambiente de subshell e sua saída (menos os caracteres de nova linha à direita) torna-se o resultado da expansão.(cmd arg)
é executado em um subshell com sua saída não afetada.Então
$((cmd arg))
seria o mesmo,$(cmd arg)
mas com uma camada extra de subshell, exceto que não é.$((...))
é uma forma separada de expansão que vem do shell Korn. No shell Korn,((arithmetic expression))
avalia a expressão aritmética (que segue uma sintaxe muito semelhante à de C) e o status de saída reflete se a expressão resolve para 0 ou diferente de zero.Isso permite coisas como:
O que o torna muito semelhante ao
C
.$
é usado para introduzir expansões . Assim como$(cmd)
é como(cmd)
exceto que se expande para a saída decmd
,$((arith))
é como((arith))
exceto que se expande para o resultado da avaliação da expressão aritmética.POSIX, cujo
sh
é principalmente baseado em ksh88, especificado,$((...))
mas não((...))
. Na verdade, em um rascunho anterior, estava indo para o$[...]
lugar, e é por isso que você encontra issobash
ezsh
suporta$[...]
como uma alternativa ao$((...))
.IIRC, a principal razão pela qual o POSIX inicialmente pensou em especificá-lo como
$[...]
é porque$((...))
entra em conflito com$((cmd arg))
, um subshell dentro de uma substituição de comando.Você verá que a maioria dos shells identifica corretamente
$((echo x; echo y) | (tr xy ab))
como não uma expansão aritmética, mas não$((cmd arg))
. Em qualquer caso$((cmd))
, pretende expandir para o valor aritmético da$cmd
variável, não para a saída decmd
.O texto relevante na especificação POSIX tem:
ksh
's((...))
também entra em conflito com subshells aninhados. Embora o POSIX não especifique((...))
, ele permite o comportamento do ksh.Na prática, ao aninhar subshells e/ou cmdsubsts, certifique-se de incluir espaço em branco entre os parênteses:
Aqui está uma demonstração de que não é executado em um subshell: você pode modificar variáveis em uma expressão aritmética:
Se fosse um subshell,
echo $x
geraria5
.Ao usar a aritmética de shell, observe que nem todos os shells suportam pré e pós-incremento;
dash
(o padrão/bin/sh
nas versões atuais do Debian e derivados) irá interpretar$(( ++i ))
como$(( +(+i) ))
e NÃO incrementar ai
variável.