2010-03-25 13 views
18

J'avais utilisé plusieurs manières de faire de l'arithmétique entière simple dans BASH (3.2). Mais je ne peux pas trouver la meilleure façon (préférée) de le faire.Expressions arithmétiques de BASH

result=`expr 1 + 2` 
result=$((1 + 2)) 
let "result = 1 + 2" 

Quelles sont les différences fondamentales entre ces expressions?
Y a-t-il d'autres façons de faire la même chose?

est l'utilisation d'un outil comme bc obligatoire pour l'arithmétique en virgule flottante?

result=`echo "7/354" | bc` 

Répondre

17

Dans Bash, let permet à plusieurs missions sur une ligne:

let a=3 b=4 c=5 

Comme vous le montrez dans votre question, citant l'argument let vous permet de mettre espaces autour des opérateurs. Vous pouvez, cependant, omettre les citations si vous évitez d'utiliser des espaces.

Une autre forme en utilisant des parenthèses doubles au début de l'instruction (au lieu de la forme i=$((j + 1))) vous permet d'inclure des espaces autour du signe égal ou faire augmentation post ou pré ou décrément et des opérations d'affectation supplémentaires:

((a = (b + c) * 4)) 
((count++)) 
((d = --c**2)) 
((e *= 2)) 
((f = 3, g = 5)) # multiple operations require a comma separator 

Si vous help "((" il dit que les doubles parenthèses est « équivalent à « let EXPRESSION ». »

Vous pouvez utiliser le declare builtin pour faire des missions, y compris indirectement:

blue=2 
name=blue 
declare $name=4 
echo $blue # result: 4 
echo ${!name} # result: 4 

Edit:

La $(()) construction est appelée "arithmetic expansion" et provoque le contenu à évaluer comme un entier expression. C'est un élément de syntaxe du shell.Si une variable est déclarée comme un entier, vous n'avez pas besoin d'utiliser une forme de parenthèses doubles, vous pouvez omettre le signe dollar du nom de la variable (comme dans les formulaires de double parenthèses), mais vous ne pouvez pas ajouter des espaces autour des opérateurs:

declare -i x=1 # set integer, initialize to 1 
declare +i s=1 # clear integer, initialize to 1 
x+=1    # could also be x=x+1 
echo $x   # result: 2 (addition) 
s+=1    # could also be s=$s+1, requires a "$" 
echo $s   # result: 11 (string concatenation) 

Contrairement aux formes ci-dessus, appelant expr implique fraie un exécutable externe qui peut être assez cher pour beaucoup de calculs dans une boucle. Le seulement temps qu'il devrait être utilisé est dans des environnements où le shell ne peut pas faire sa propre arithmétique ou pour la portabilité lorsqu'un script peut trouver son chemin dans un tel environnement. Les shells POSIX ont une capacité arithmétique donc ce ne serait une préoccupation qu'avec les anciens systèmes. En ce qui concerne l'utilisation de bc pour l'arithmétique en virgule flottante, il est nécessaire de l'utiliser, ou quelque chose de similaire, lors de l'utilisation de Bash et de nombreuses autres coques. POSIX dit que "Seule l'arithmétique des nombres entiers longs est obligatoire."

Deux shells qui supportent les maths float sont ksh et zsh. En plus de bc, vous pouvez utiliser dc, AWK, Python, Perl et d'autres dans un script Bash.

Une chose qui Bash va faire avec des nombres à virgule flottante est de les imprimer avec le printf builtin (notez qu'il ya aussi un printf externe, mais builtins priorité).

printf "%'14.4f\n" 1234.56 # result " 1,234.5600" (in my locale) 
+0

Vous avez omis de discuter des implications de spawning 'expr' etc. et de savoir si' $ (()) 'est un bultin ou non. – vladr

+0

@Vlad: J'espère que vous trouverez les ajouts une amélioration. –

+0

merci pour les ajouts. :) +1 – vladr

4

Je ne peux pas dire qu'il est « obligatoire » mais bc est probablement votre meilleur pari pour usage général arithmétique.

Pour quelque chose de fantaisiste, vous pouvez toujours passer par Perl. L'inconvénient de ces deux approches est qu'elles ouvrent toutes les deux un processus fils, donc le faire dans une boucle serrée sera plus lent que les expressions bash natives (le même problème se pose avec l'utilisation de backticks, dans votre premier exemple). Je ne suis pas sûr si $(()) appelle un processus enfant.

5

Je préfère votre deuxième option, car il n'a pas besoin d'un utilitaire externe:

result=$((1 + 2)) 

La première option appelle à expr faire le calcul - Je ne suis pas familier avec let. Une autre alternative à bc est dc. Choisissez votre favori.

0

La troisième option que vous avez est beaucoup moins lisible car il ne ressemble pas à un opérateur d'affectation. Le premier, comme indiqué par d'autres, appelle une commande externe

3

Is the use of a tool like bc mandatory for floating point arithmetic?

Non, si vous utilisez un shell qui prend en charge à virgule flottante, par exemple zsh, ksh. Sinon, si vous souhaitez effectuer des calculs en virgule flottante plus avancés, utilisez l'une de ces méthodes, bc/awk/dc. Bien sûr, Perl/Python etc.