Em shell script, podemos substituir expr $a*$b
por $(($a+$b))
.
Mas por que não apenas com (($a+$b))
, porque em qualquer recurso está escrito que (())
é para computação inteira.
Portanto, usamos $(())
quando há variáveis em vez de valores inteiros, certo? E o que devemos usar em vez de $(())
quando as variáveis podem receber valores flutuantes?
Comentários
- Veja também unix.stackexchange.com/questions/149823/…
Resposta
-
Para aritmética,
expr
é arcaico. Não use. * -
$((...))
e((...))
são muito semelhantes. Ambos fazem apenas cálculos inteiros. A diferença é que$((...))
retorna o resultado do cálculo e((...))
não. Portanto,$((...))
é útil emecho
declarações:$ a=2; b=3; echo $((a*b)) 6
((...))
é útil quando você deseja atribuir uma variável ou definir um código de saída:$ a=3; b=3; ((a==b)) && echo yes yes
-
Se você deseja flutuar cálculos de pontos, use
bc
ouawk
:$ echo "4.7/3.14" | bc -l 1.49681528662420382165 $ awk "BEGIN{print 4.7/3.14}" 1.49682
* Como um aparte, expr
permanece útil para o tratamento de strings quando globs não são bons o suficiente e um método POSIX é necessário para lidar com expressões regulares.
Comentários
- Se expr for arcaico, o que devemos usar em vez do texto expr: '. * '
- Se
s
for uma variável shell, seu comprimento será${#s}
- $ {#} significa um número de argumentos e $ (# s} significa um número de caracteres de uma variável, não é?
- Sim. Isso ' está certo.
- @Stranger Muitos usos de
expr STRING : REGEX
podem ser escritos comocase STRING in PATTERN)
.expr
só é útil quando REGEX pode ' t ser expresso com curingas de shell.
Resposta
expr é antigo, mas tem um uso limitado que posso imaginar. Digamos que você queira pesquisar uma string. Se você quiser ficar POSIX com grep, você precisa usar um pipe:
if echo november | grep nov then : do something fi
expr pode fazer isso sem um pipe:
if expr november : nov then : do something fi
o único problema é que expr funciona com strings ancoradas, então, se você quiser combinar após o início, você precisa alterar o REGEXP:
if expr november : ".*ber" then : do something fi
Em relação a (( ))
, esta construção não é POSIX , portanto deve ser evitada.
Com relação a $(( ))
, você não precisa incluir o cifrão:
$ fo=1 $ go=2 $ echo $((fo + go)) 3
Comentários
- Muitos usos de
expr STRING : REGEX
podem ser escritos comocase STRING in PATTERN)
.expr
só é útil quando REGEX pode ' t ser expresso com curingas de shell.
Resposta
Parece que os programas a seguir fazem mais ou menos o mesmo e realmente não diferem. Mas isso não é verdade.
#!/bin/bash s=-1000 for (( i=0; i<1000000; i++ )), do s=$((s+1)) echo $s
Esta é a maneira correta de implementar isso. A expressão s + 1 é avaliada pelo shell e pode ser atribuída a uma variável.
#!/bin/bash s=-1000 for (( i=0; i<1000000; i++ )), do s=`expr $s+1` echo $s
Aqui a expressão será calculada pelo programa expr, que não é um shell embutido, mas um programa Unix externo. Portanto, em vez de simplesmente adicionar 1 es, um programa deve ser iniciado e sua saída deve ser lida e gravada na variável. Iniciar um programa requer muitos recursos e muito tempo. E este programa é executado 1.000.000 de vezes. Portanto, o programa será muito mais lento que o anterior. No entanto, o código funciona corretamente.
#!/bin/bash -e s=-1000 for (( i=0; i<1000000; i++ )), do ((s=s+1)) echo $s
Se o sinalizador -e não estiver definido, o programa também funcionará corretamente. Mas se -e for definido quando s = -1 e ((s = s + 1)) é calculado. A expressão s = s + 1 avalia como 0 e o código de saída de ((0)) é> 0, o que é interpretado como um erro pelo shell e o shell sai do programa.
A razão para definir o sinalizador -e é que é a maneira mais simples de processamento de erro: pare se ocorrer um erro.