Par défaut le Bash traite toutes les valeurs comme des chaînes de caractères. Plusieurs solutions existent pour effectuer des opérations arithmétiques.
expr est une commande qui prend pour arguments chaque terme de l'expression arithmétique. Pour évaluer correctement cette expression, chaque opérande et chaque opérateur doit être séparé par un espace:
# Pour que expr puisse interpréter correctement l'expression # chaque opérande et opérateurs de l'expression mathématique # doivent être des arguments séparés $ expr 3 + 2 5 # Attention a bien inhiber le métacaractère '*' qui a une signification # pour le shell. Il ne doit pas être interprété et passé tel quel à la # commande expr $ expr 3 \* 2 6 # Ici expr est invoquée sans séparer les termes. Un seul argument # sans signification pour expr, il n'est pas évalué $ expr 3+2 3+2 # Les parenthèses sont des caractères spéciaux pour le shell. # Il faut donc empêcher le shell de les traiter. $ expr \( 10 + 6 \) / 2 8
expr est une commande externe, son choix est pertinent lorsque des contraintes de portabilité du code existent.
Le shell Bash est capable d'évaluer une expression arithmétique et de la substituer par le résultat. La syntaxe de la substitution arithmétique en Bash:
$(( expression ))
Elle présente quelques avantages:
$ a=2 ; b=3 $ i=$((a*b)) $ echo $i 6
Les expressions arithmétiques sont évaluées par la commande interne let “expression” qui s’abrège via la syntaxe ((expression)). Contrairement à la substitution arithmétique la commande let n’effectue aucune sortie. Ainsi l’expression peut être une affectation sans provoquer d’erreur:
# affectation avec let ((i=1+2)) # L'usage de la substitution arithmétique pour cette même # affectation provoque une erreur car après substitution, # le shell essai d’interpréter le résultat qui n'est pas # une commande valide $((i=1+2)) 2 : commande introuvable # usages équivalents let "a=a+1" let "a+=1" ((a++))
La commande let permet de faire davantage que des calculs sur des entiers. Comme toutes les commandes des systèmes Unix, une fois exécutée la commande retourne un code d’état dans la variable $?. Lorsque l’expression est une expression booléenne, le code retour prend la valeur 0 pour les cas où l’évaluation de l’expression a pour valeur vraie.
$ a=33 $ ((a==12)) $ echo $? 1
Par défaut les valeurs manipulées par le shell sont des chaîne de caractères. Il est cependant possible de déclarer une variable de type entier relatif. Avec les variables typées entier, il sera possible d’effectuer des opérations arithmétiques sans avoir recours aux commandes expr ou let.
$ declare -i b=33 $ b=b+3 $ echo $b 36
$
.
Outre une évaluation implicite (sans avoir recours à la commande let), la déclaration de variable assure que la valeur est toujours un entier (relatif). Si une chaîne de caractères non numérique est affectée, la conversion en valeur entière donnera la valeur 0.
$ declare -i a $ a=essai $ echo $a 0
expr et le shell peuvent faire des calculs sur des nombres entiers. Dans l’utilisation courante d’un shell qui vise à faire des comptages, c’est bien suffisant. Mais s’il est nécessaire de faire des calculs scientifiques, il faut avoir recours à la commande dédiée bc.
bc peut être utilisée en mode interactif ou en mode commande.
# invoque bc en mode interactif sans affichage # de la bannière d'accueil $ bc -q # Invoquer bc en mode commande en fournissant les # commandes sur son entrée standard. # NB: Pour prendre en compte les décimales, il faut spécifier # la précision par la directive scale. En indiquant scale=10, # la commande bc codera les nombres sur une précision de 10 décimales. $ b=10 $ echo "scale=5 ; $b/3" | bc 3.33333