Diferença entre let, expr e $ []

23

Eu quero saber qual é exatamente a diferença entre

a=$[1+1]
a=$((1+1))
let a=1+1
a=$(expr 1 + 1 )

Todos os 4 atribuem a variável a com 2, mas qual é a diferença?

Pelo que descobri até agora, é que o expr é mais lento porque não é um shell real embutido. Mas nada além disso.

ADDB
fonte

Respostas:

25

Tudo isso lida com aritmética, mas de maneiras diferentes e a variável é criada por diferentes meios. Alguns deles são específicos para bashconchas, enquanto outros não.

  • $((...))é chamado de expansão aritmética , o que é típico das conchas bashe ksh. Isso permite fazer aritmética inteira simples , sem nenhum ponto flutuante. O resultado da expressão substitui a expressão, pois echo $((1+1))se tornariaecho 2
  • ((...))é referido como avaliação aritmética e pode ser usado como parte de if ((...)); thenou while ((...)) ; dodeclarações. A expansão de expansão aritmética $((..))substitui a saída da operação e pode ser usada para atribuir variáveis ​​como em, i=$((i+1))mas não pode ser usada em instruções condicionais.
  • $[...] é a sintaxe antiga da expansão aritmética que está obsoleta. Veja também . Isso provavelmente foi mantido para que os bashscripts antigos não quebrem. Como não funcionou ksh93, acho que essa sintaxe é específica do bash. NOTA : os espaços são muito importantes aqui; não confunda $[1+1]com coisas assim [ $a -eq $b ]. Os [espaços com são conhecidos como testcomando e você normalmente o vê nas partes de tomada de decisão. É muito diferente em comportamento e propósito.
  • leté uma palavra bash- kshchave e que permite a criação de variáveis ​​com avaliação aritmética simples. Se você tentar atribuir uma string lá, let a="hello world"receberá um erro de sintaxe. Trabalha em bashe ksh93.
  • $(...)é substituição de comando, onde você literalmente pega a saída de um comando e atribui a uma variável. Seu comando aqui é expr, que recebe argumentos posicionais, como expr arg1 arg2 arg3, portanto, os espaços são importantes. É como uma pequena calculadora de linha de comando para aritmética inteira, além de alguns tipos de coisas reais / falsas e regex. Este é um comando neutro em shell.

Também é importante notar que a expansão aritmética e a substituição de comandos são especificadas pelo padrão POSIX , enquanto lete $[...]não são.

Sergiy Kolodyazhnyy
fonte
1
((...))realmente pode ser usado para tarefas em bash, kshe zsh: n=10; ((n+=10)); echo $nimprime 20 e ((x=1)); echo $ximprime 1.
Alexej Magura 06/12
1
@Alexej Obrigado. Resposta atualizada, essa parte removida
Sergiy Kolodyazhnyy 8/12
11
  • letO comando executa avaliação aritmética e é um shell embutido.

    • Execute este comando e você não obtém nada (apenas avalia):

      let 1+2
  • $(( ))é usado para executar expansão aritmética : leia aqui

    • Execute este e você receberá um erro (devido à expansão):

      $((1+2))
  • $[ ] é a sintaxe antiga para expansão aritmética:

    O formato antigo $ [expression] foi descontinuado e será removido no lançamento do bash. Bash Man Page

  • expr é um comando binário, se você deseja fazer uma expansão aritmética em uma subsituação de comando, pode usá-lo:

    echo $(expr 1 + 2) 
    echo `expr 1 + 2`
Ravexina
fonte
4

Como algumas das respostas acima mencionam especificamente ksh93, vale a pena notar que ele pode fazer matemática de ponto flutuante, por exemplo:

$ print $((1.0/3)) 
0.333333333333333333

Você pode controlar a precisão da saída com printf, por exemplo:

$ printf "%.4f\n" $((1.0/3))
0.3333

Pelo menos um argumento deve ser especificado como um número de ponto flutuante como acima. Se ambos forem especificados como números inteiros, somente a matemática inteira será feita, por exemplo:

$ print $((1/3))  
0

Isso pode ser útil quando você precisar de matemática de ponto flutuante em um script de shell, pois pode evitar chamar um comando externo.

espirroso
fonte
Ocorre-me que você pode estar interessado em postar uma resposta para Posso usar frações / decimais em um script bash? Apesar do título, acho que o contexto deixa claro que outras conchas no estilo Bourne são relevantes, e foi por isso que postei uma zshresposta . Desde kshe bashsão mais semelhantes entre si (em geral) do que qualquer um é zsh, parece-me que uma kh93resposta baseada a essa pergunta poderia ser bastante útil.
Eliah Kagan 28/09
1

letnão funciona no cron. Eu acho que é devido a letter seu próprio ambiente. Use $((...))uma vez que é POSIX. Por exemplo,

let x=1+2
echo x=$x

no cron, resulta em "x =", mas "x = 3" quando executado a partir do shell.

x=$((1+2))
echo x=$x

resulta em "x = 3" em todos os casos.

SparkEV
fonte