web-dev-qa-db-fra.com

Parenthèses en arithmétique expr: 3 * (2 + 1)

expr ne semble pas aimer les parenthèses (utilisées en mathématiques pour donner la priorité explicite aux opérateurs):

expr 3 * (2 + 1)
bash: syntax error near unexpected token `('

Comment exprimer la priorité de l'opérateur en bash?

64
Nicolas Raoul

Une autre façon d'utiliser let bash builtin:

$ let a="3 * (2 + 1)"
$ printf '%s\n' "$a"
9

Remarque

Comme @ Stéphane Chazelas l'a souligné , dans bash vous devez utiliser ((...)) Pour faire de l'arithmétique sur expr ou let pour la lisibilité.

Pour la portabilité, utilisez $((...)) comme @ réponse Bernhard .

41
cuonglm

Vous pouvez utiliser l'expansion arithmétique à la place.

echo "$(( 3 * ( 2 + 1 ) ))"
9

À mon avis, cela semble un peu plus agréable que d'utiliser expr.

De man bash

Expansion arithmétique L'expansion arithmétique permet l'évaluation d'une expression arithmétique et la substitution du résultat. Le format de l'expansion arithmétique est le suivant:

         $((expression))

L'expression est traitée comme si elle se trouvait entre guillemets doubles, mais un guillemet double entre parenthèses n'est pas traité spécialement. Tous les jetons de l'expression subissent une expansion de paramètre, une expansion de chaîne, une substitution de commande et une suppression de devis. Les extensions arithmétiques peuvent être imbriquées.

L'évaluation est effectuée selon les règles énumérées ci-dessous sous ÉVALUATION ARITHMÉTIQUE. Si l'expression n'est pas valide, bash imprime un message indiquant l'échec et aucune substitution ne se produit.

79
Bernhard

Il n'y a aucune raison d'utiliser expr pour l'arithmétique dans les shells modernes.

POSIX définit l'opérateur d'expansion $((...)). Vous pouvez donc l'utiliser dans tous les shells compatibles POSIX (le sh de tous les likes Unix modernes, dash, bash, yash, mksh, zsh, posh, ksh ...).

a=$(( 3 * (2 + 1) ))
a=$((3*(2+1)))

ksh a également introduit une fonction intégrée let qui reçoit le même type d'expression arithmétique, ne se développe pas en quelque chose mais renvoie un état de sortie selon que l'expression se résout à 0 ou non, comme dans expr:

if let 'a = 3 * (2 + 1)'; then
  echo "$a is non-zero"
fi

Cependant, comme la citation la rend maladroite et peu lisible (pas dans la même mesure que expr bien sûr), ksh a également introduit une forme alternative ((...)):

if (( a = 3 * (2 + 1) )) && (( 3 > 1 )); then
  echo "$a is non-zero and 3 > 1"
fi
((a+=2))

qui est beaucoup plus lisible et devrait être utilisé à la place.

let et ((...)) sont uniquement disponibles dans ksh, zsh et bash. La syntaxe $((...)) doit être préférée si la portabilité vers d'autres shells est nécessaire, expr n'est nécessaire que pour les shells de type Bourne pré-POSIX (généralement le Bourne Shell ou les premières versions du Almquist Shell) .

Sur le front non Bourne, il y a quelques coques avec opérateur arithmétique intégré:

  • csh/tcsh (en fait le premier Unix Shell avec évaluation arithmétique intégrée):

    @ a = 3 * (2 + 1)
    
  • akanga (basé sur rc)

    a = $:'3 * (2 + 1)'
    
  • comme note d'histoire, la version originale de l'Almquist Shell, telle que publiée sur usenet en 1989 avait un expr intégré (en fait fusionné avec test), mais il a été supprimé plus tard.

40
Stéphane Chazelas

expr est une commande externe, ce n'est pas une syntaxe Shell spéciale. Par conséquent, si vous souhaitez que expr affiche les caractères spéciaux de Shell, vous devez les protéger de l'analyse syntaxique de Shell en les citant. De plus, expr a besoin que chaque nombre et opérateur soit passé comme paramètre séparé. Donc:

expr 3 \* \( 2 + 1 \)

À moins que vous ne travailliez sur un système Unix antique des années 1970 ou 1980, il y a très peu de raisons d'utiliser expr. Autrefois, les shells n'avaient pas de méthode intégrée pour effectuer l'arithmétique, et vous deviez plutôt appeler l'utilitaire expr. Tous les shells POSIX ont une arithmétique intégrée via la syntaxe expansion arithmétique .

echo "$((3 * (2 + 1)))"

La construction $((…)) se développe jusqu'au résultat de l'expression arithmétique (écrite en décimal). Bash, comme la plupart des shells, ne prend en charge que le module arithmétique entier 264 (ou modulo 232 pour les anciennes versions de bash et certains autres shells sur les machines 32 bits).

Bash offre une syntaxe de commodité supplémentaire lorsque vous souhaitez effectuer des affectations ou tester si une expression est 0 mais ne vous souciez pas du résultat. Cette construction existe également en ksh et zsh mais pas en plain sh.

((x = 3 * (2+1)))
echo "$x"
if ((x > 3)); then …

En plus de l'arithmétique entière, expr propose quelques fonctions de manipulation de chaînes. Celles-ci sont également incluses dans les fonctionnalités des shells POSIX, sauf une: expr STRING : REGEXP Teste si la chaîne correspond à l'expression rationnelle spécifiée. Un shell POSIX ne peut pas faire cela sans outils externes, mais bash peut avec [[ STRING =~ REGEXP ]] (Avec une syntaxe regexp différente - expr est un outil classique et utilise BRE, utilise bash AVANT).

À moins que vous ne mainteniez des scripts qui s'exécutent sur des systèmes vieux de 20 ans, vous n'avez pas besoin de savoir que expr a jamais existé. Utilisez l'arithmétique Shell.

Utilisez des parenthèses avec des guillemets:

expr 3 '*' '(' 2 '+' 1 ')'
9

Les guillemets empêchent bash d'interpréter la parenthèse comme une syntaxe bash.

13
Nicolas Raoul

Si vous avez bc ..

echo '3 * (2 + 1)'|bc 
9                                                                    
1
rob