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 emechodeclaraçõ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
bcouawk:$ 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
sfor 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 : REGEXpodem ser escritos comocase STRING in PATTERN).exprsó é ú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 : REGEXpodem ser escritos comocase STRING in PATTERN).exprsó é ú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.