Parenthèses dans larithmétique expr: 3 * (2 + 1)

expr ne semble pas aimer les parenthèses (utilisées en mathématiques à la priorité dopérateur explicite):

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

Comment exprimer la priorité dopérateur dans bash?

Réponse

Une autre façon dutiliser let bash builtin:

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

Remarque

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

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

Commentaires

  • +1 Encore plus lisible! Jai posté ma question + réponse en pensant que cela serait utile pour mes collègues utilisateurs de Linux, mais maintenant je tire beaucoup davantages des autres réponses 🙂
  • Là ‘ na aucune raison dutiliser let. Il ‘ nest plus standard ou portable que (( a = 3 * (2 + 1) )) (les deux proviennent de ksh et sont uniquement disponibles en ksh, bash et zsh) et ‘ est moins lisible ou facile à citer. Utilisez a=$((3 * (2 + 1))) pour être portable.
  • Je ‘ je ne le dis pas ‘ est faux, je ‘ je dis simplement quil ne devrait pas être utilisé car il existe de meilleures alternatives (une pour la lisibilité ((a = 3 * (2 + 1) )), une pour la portabilité a=$((3 * (2 + 1)))), donc ce ‘ nest pas une note contre vous ou votre réponse mais contre le fait que ce soit la réponse sélectionnée et le meilleur buteur .
  • @St é phaneChazelas: Mise à jour de ma réponse!
  • Jai toujours utilisé a=1 $[a+2] ou a=1 b=2 $[a+b]. Leur raison est-elle déviter cette syntaxe?

Réponse

Vous pouvez utiliser lexpansion arithmétique à la place.

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

À mon avis personnel, cela semble un peu plus agréable que dutiliser expr.

De man bash

Extension arithmétique Le développement arithmétique permet lévaluation dune expression arithmétique et la substitution du résultat. Le format pour le développement arithmétique est:

 $((expression)) 

Lexpression est traitée comme si elle était entre guillemets, mais un guillemet double entre parenthèses nest pas traité spécialement. Tous les jetons de lexpression subissent une expansion des paramètres, une expansion de chaîne, une substitution de commande et une suppression de guillemets. 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 lexpression nest pas valide, bash affiche un message indiquant un échec et aucune substitution na lieu.

Commentaires

  • En plus de la lisibilité, cela ne nécessite pas ‘ t de forger un processus supplémentaire pour faire larithmétique; il ‘ est géré par le shell lui-même.
  • Notez que dans les shells POSIX, il ‘ est soumis à word fractionnement, donc cest ‘ une bonne habitude de le citer dans des contextes de liste.
  • Quand jessaye ceci au shell bash, jobtiens ‘ Nom de variable illégal.  »

Réponse

Il ny a aucune raison dutiliser expr pour larithmétique dans les shells modernes.

POSIX définit le $((...)) opérateur dexpansion. Vous pouvez donc lutiliser dans tous les shells compatibles POSIX (le sh de tous les goûts Unix modernes, dash, bash, yash, mksh, zsh, posh, ksh … ).

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

ksh a également introduit un let intégré qui reçoit le même type dexpression arithmétique, ne se développe pas en quelque chose mais renvoie un état de sortie basé sur la résolution de lexpression es à 0 ou pas, comme dans expr:

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

Cependant, comme les guillemets le rendent maladroit et non très lisible (pas dans la même mesure que expr bien sûr), ksh a également introduit un ((...)) 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ée à la place.

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

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

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

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

    a = $:"3 * (2 + 1)" 
  • comme note historique, la version originale du shell Almquist, 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.

Commentaires

  • Japprends quelque chose de nouveau chaque jour de toi, St é phane. Japprécie beaucoup votre connaissance du shell POSIX!
  • Que diriez-vous de : $((a = a*2))?
  • Et si jai une virgule flottante? Mon expression est a = $ ((-14 + 0,2 * (1 + 2 + 3))). Le jeton derreur est  » .2 * (1 + 2 + 3)  »
  • @Blaise, alors vous ‘ d besoin dun shell qui prend en charge les virgules flottantes dans $((...)) comme zsh, ksh93 ou yash.

Réponse

expr est une commande externe, ce nest pas une syntaxe shell spéciale. Par conséquent, si vous voulez expr voir les caractères spéciaux du shell, vous devez les protéger de lanalyse du shell en les citant. De plus, expr a besoin que chaque numéro et chaque opérateur soient passés en tant que paramètre séparé. Ainsi:

expr 3 \* \( 2 + 1 \) 

À moins que vous « ne travailliez sur un ancien système unix des années 1970 ou 1980, il y a très peu de raisons dutiliser expr. Dans lancien temps, les shells navaient pas de méthode intégrée pour effectuer des calculs arithmétiques, et vous deviez appeler lutilitaire expr à la place. Tous les shells POSIX ont une arithmétique intégrée via la syntaxe expansion arithmétique .

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

Le construct $((…)) se développe au résultat de lexpression arithmétique (écrite en décimal). Bash, comme la plupart des shells, ne prend en charge que larithmétique entière modulo 2 64 (ou modulo 2 32 pour les anciennes versions de bash et certains autres shells sur les machines 32 bits).

Bash propose une syntaxe de commodité supplémentaire lorsque vous voulez 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 sh simple.

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

En plus de larithmétique entière, expr propose quelques fonctions de manipulation de chaînes. Celles-ci sont également subsumées par les fonctionnalités des shells POSIX, sauf une: expr STRING : REGEXP teste si la chaîne correspond à lexpression rationnelle spécifiée. Un shell POSIX ne peut pas le faire sans outils externes, mais bash le peut avec [[ STRING =~ REGEXP ]] (avec une syntaxe dexpression régulière différente expr est un outil classique et utilise BRE, bash utilise ERE).

À moins que vous ne mainteniez des scripts fonctionnant sur des systèmes vieux de 20 ans, vous n’avez pas besoin de savoir que expr a jamais existé. Utilisez larithmétique du shell.

Commentaires

  • expr foo : '\(.\)' effectue également lextraction de texte. bash ‘ s BASH_REMATCH réalise quelque chose de similaire. Il effectue également une comparaison de chaînes, ce que POSIX [ ne fait pas (bien que lon puisse imaginer des façons dutiliser sort pour cela).
  • trait de soulignement comme espace réservé de syntaxe — vous êtes un Schemer, @Giles? :]
  • @RubyTuesdayDONO Je nai ‘ pas utilisé de trait de soulignement ici. Avez-vous mal lu U + 2026 HORIZONTAL ELLIPSIS? Si cest le cas, essayez dutiliser une police plus grande.
  • @Giles – daccord, oui, cela ne ressemble quà un trait de soulignement à cause de ma taille de police. pour moi,  » Schemer  » est un complément, et ce ‘ nest pas comme des points de suspension versus le soulignement change la signification de toute façon… pas besoin dêtre sournois dessus: /

Réponse

Utilisez des parenthèses avec guillemets:

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

Les guillemets empêchent bash dinterpréter les parenthèses comme une syntaxe bash.

Commentaires

  • Ce que Nicolas illustre mais nexplique pas, cest que les jetons sur la ligne de commande expr doivent être séparés par des espaces; alors; par exemple, expr 3 "*" "(2" "+" "1)" ne fonctionnera pas . (En outre, BTW, vous navez probablement pas besoin de citer le +.)
  • Les parenthèses ne sont pas ‘ t mots-clés tels que while et [[, ils ‘ reprennent la syntaxe. Sil sagissait de mots-clés, ils ne seraient ‘ pas interprétés comme tels dans les arguments de commande. Vous avez besoin de guillemets pour que bash ne ‘ ne les analyse pas mais voit plutôt une chaîne littérale.

Réponse

Si vous avez bc ..

echo "3 * (2 + 1)"|bc 9 

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *