comment puis-je ajouter (soustraire, etc.) deux nombres avec bash?

90

Je peux lire les chiffres et les opérations avec:

echo "First number please"
read num1
echo "Second number please"
read num2
echo "Operation?"
read op

mais alors toutes mes tentatives pour ajouter les nombres échouent:

case "$op" in
  "+")
    echo num1+num2;;
  "-")
    echo `num1-num2`;;
esac

Courir:

First number please
1
Second mumber please
2
Operation?
+

Sortie:

num1+num2

...ou...

echo $num1+$num2;;

# results in: 1+2    

...ou...

echo `$num1`+`$num2`;;

# results in: ...line 9: 1: command not found

On dirait que je reçois encore des chaînes quand j'essaie d'ajouter add add ("2 + 2" au lieu de "4").

Michael Durrant
la source
5
J'ai édité votre titre parce que c'est une bonne question générale, et si vous aviez réduit le contexte, vous vous seriez rendu compte que cela n'avait rien à voir caseou rien sauf une ligne:, echo $num+$numpuisque cela reproduirait exactement le problème . L'idée de minimiser le contexte dans les questions de programmation est expliquée ici: sscce.org
goldilocks
2
+1 Coucou, c’est devenu clair pour moi par la suite, mais oui, je suis tout à fait d’accord avec votre raisonnement et oui, plus une question est spécifique et «singulière», mieux elle l’est. Je vous souhaite la bienvenue :) merci :)
Michael Durrant le

Réponses:

117

L'arithmétique dans les shells POSIX est faite avec des $doubles parenthèses (( )):

echo "$(($num1+$num2))"

Vous pouvez assigner à partir de cela (sans echo):

num1="$(($num1+$num2))"

Il y a aussi expr:

expr $num1 + $num2

Dans le script $(())est préférable car il évite un fork / execute pour la exprcommande.

boucle d'or
la source
Ou même directement echo $(($num1$op$num2))sans impliquer case.
manatwork
Il n'y a pas caseimpliqué ici.
goldilocks
1
Non, mais vous avez utilisé littéral +, vous aurez donc besoin de l' caseextérieur pour gérer la soustraction séparément.
manatwork
1
@manatwork: Vous voulez dire éliminer le casecode du code opérateur avec echo $(($num1$op$num2))- cela fonctionnera, mais son utilisation caseest plus robuste, car vous pouvez gérer les erreurs avec un paramètre par défaut *.
goldilocks
+1 à vous deux. J'utilisais case (je ne l'avais peut-être pas montré au début), mais vous vous êtes rendu compte que le problème ne concernait pas le cas.
Michael Durrant
13

La réponse existante est pure bash, elle sera donc plus rapide que cela, mais elle ne peut gérer que des entiers. Si vous avez besoin de manipuler des floats, vous devez utiliser le programme externe bc.

$ echo 'scale=4;3.1415+9.99' | bc
13.1315

Le scale=4dit bcd'utiliser quatre décimales. Voir man bcpour plus d'informations.

maux de tête
la source
Notez que tout bashne prend pas en charge à virgule flottante avec Arithmétique $((...)), beaucoup de coquilles ( ksh93, zsh, yashau moins) faire. L'avantage bcest qu'il prend en charge une précision arbitraire alors que l'arithmétique shell est limitée au doubletype de processeur . Notez que vous n'avez pas besoin de définir scaleici. Pour les ajouts, le scaleparamètre n'est pas utilisé. L'échelle de 3.1415+9.99sera dérivée de celle des opérandes (ici 4).
Stéphane Chazelas
Comment faire le calcul si une valeur est 450et que l'autre est le nombre décimal stocké sur une variable $mynumber? Par exemple, 450-$mynumber.
Sigur
@sigur echo "450-$mynumber" | bcdevrait le faire. Si vous souhaitez développer une variable, vous devez utiliser des guillemets plutôt que des guillemets simples.
Evilsoup
@ Evilsoup, cela fonctionne maintenant comme un charme. Merci.
Sigur
computedval=$(echo 'scale=10;var1-var2' | bc)ne fonctionne pas, ni ne fonctionnecomputedval=$(echo 'scale=10;$var1-$var2' | bc)
StatsSorceress
5
echo `expr $a + $b`   
echo `expr $a - $b`   
echo `expr $a \* $b`   
echo `expr $a / $b`   

Notez le \avant le *(pour la multiplication), l'expression entière doit être dans les guillemets arrières `.

Himani
la source
1
exprn'est pas nécessaire et il n'est jamais nécessaire de capturer la sortie standard d'une commande pour la réécrire dans la sortie standard.
Chepner
2

minimaliste

total=0
((total+=qty))
geekzspot
la source
1

Vous pouvez également utiliser la $[ ... ]structure. Dans ce cas, nous utilisons le mécanisme intégré dans Bash, qui est plus rapide et un peu plus pratique à utiliser. Puisque nous savons que tout ce qui est entre $ [et] est traité comme une expression, nous n’avons pas besoin de faire précéder les variables $. De même, nous n'avons pas besoin de nous assurer *de ne pas le traiter comme un motif.

num1=2
num2=3
echo $[num1 + num2]
5
Jedi
la source
0

En fonction de la séquence d'entrées que vous demandez à l'utilisateur, il semble que vous utilisiez la notation polonaise inversée.

echo "First number please"
read num1
echo "Second number please"
read num2
echo "Operation?"
read op

Vous feriez mieux de simplement utiliser dc(calculatrice de bureau) directement, puisque c’est à quoi cela sert.

DESCRIPTION
       Dc is a reverse-polish desk calculator which supports unlimited pre-
       cision arithmetic.

Exemple de session utilisant dc:

$ dc
1 2 + p    # This part is typed; the result comes next.
3
q  # This is also typed.
$

Ou, de manière non interactive:

$ dc -e '1 2 + p'
3
$
Wildcard
la source