Usando expr, $ (()), (()) (Português)

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

Resposta

  1. Para aritmética, expr é arcaico. Não use. *

  2. $((...)) 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 em echo 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 
  3. Se você deseja flutuar cálculos de pontos, use bc ou awk:

    $ 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 como case 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 como case 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.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *