Différence entre let, expr et $ []

23

Je veux savoir quelle est exactement la différence entre

a=$[1+1]
a=$((1+1))
let a=1+1
a=$(expr 1 + 1 )

Tous les 4 attribuent la variable a à 2, mais quelle est la différence?

D'après ce que j'ai découvert jusqu'à présent, c'est que expr est plus lent car ce n'est pas un véritable shell intégré. Mais rien de plus que cela.

ADDB
la source

Réponses:

25

Tous ces éléments traitent de l'arithmétique, mais de différentes manières et la variable est créée par différents moyens. Certains d'entre eux sont spécifiques aux bashobus, tandis que d'autres ne le sont pas.

  • $((...))est appelé expansion arithmétique , qui est typique des coquilles bashet ksh. Cela permet de faire simple , entier arithmétique, pas de choses à virgule flottante cependant. Le résultat de l'expression remplace l'expression, car en echo $((1+1))deviendraitecho 2
  • ((...))est appelé évaluation arithmétique et peut être utilisé dans le cadre de if ((...)); thenou d' while ((...)) ; doinstructions. L'expansion arithmétique l'expansion $((..))remplace la sortie de l'opération et peut être utilisée pour affecter des variables comme dans i=$((i+1))mais ne peut pas être utilisée dans les instructions conditionnelles.
  • $[...] est l'ancienne syntaxe pour l'expansion arithmétique qui est déconseillée. Voir aussi . Cela a probablement été conservé afin que les anciens bashscripts ne se cassent pas. Cela n'a pas fonctionné ksh93, donc je suppose que cette syntaxe est spécifique à bash. REMARQUE : les espaces sont très importants ici; ne confondez pas $[1+1]avec des trucs comme [ $a -eq $b ]. L' [espace avec est connu sous le nom de testcommande, et vous le voyez généralement dans les parties de prise de décision. Le comportement et le but sont très différents.
  • letest un mot clé bashet kshqui permet la création de variables avec une évaluation arithmétique simple. Si vous essayez d'affecter une chaîne ici comme let a="hello world"vous obtiendrez une erreur de syntaxe. Fonctionne dans bashet ksh93.
  • $(...)est la substitution de commande, où vous prenez littéralement la sortie d'une commande et l'assignez à une variable. Votre commande ici est expr, qui prend des arguments positionnels, comme expr arg1 arg2 arg3, donc les espaces sont importants. C'est un peu comme une petite calculatrice en ligne de commande pour l'arithmétique entière, plus du vrai / faux et du type d'expression régulière. Il s'agit d'une commande sans shell.

Il convient également de noter que l'expansion arithmétique et la substitution de commandes sont spécifiées par la norme POSIX , tandis que letet $[...]ne le sont pas.

Sergiy Kolodyazhnyy
la source
1
((...))en fait, peut être utilisé pour des affectations dans bash, kshet zsh: n=10; ((n+=10)); echo $nimprime 20 et ((x=1)); echo $ximprime 1.
Alexej Magura
1
@Alexej Merci. Réponse mise à jour, cette partie supprimée
Sergiy Kolodyazhnyy
11
  • letLa commande effectue une évaluation arithmétique et est un shell intégré.

    • Exécutez cette commande et vous n'obtenez rien (n'évalue que):

      let 1+2
  • $(( ))est utilisé pour effectuer une expansion arithmétique : lire ici

    • Exécutez celui-ci et vous obtiendrez une erreur (en raison de l'expansion):

      $((1+2))
  • $[ ] est l'ancienne syntaxe pour l'expansion arithmétique:

    L'ancien format $ [expression] est obsolète et sera supprimé dans les prochains bash. Page de manuel de Bash

  • expr est une commande binaire, si vous voulez faire une expansion arithmétique dans une sous-position de commande, vous pouvez l'utiliser:

    echo $(expr 1 + 2) 
    echo `expr 1 + 2`
Ravexina
la source
4

Étant donné que certaines des réponses ci-dessus mentionnent spécifiquement, ksh93il convient de noter qu'il peut effectuer des calculs en virgule flottante, par exemple:

$ print $((1.0/3)) 
0.333333333333333333

Vous pouvez contrôler la précision de la sortie avec printf, par exemple:

$ printf "%.4f\n" $((1.0/3))
0.3333

Au moins un argument doit être spécifié comme un nombre à virgule flottante comme ci-dessus. Si les deux sont spécifiés comme des nombres entiers, seuls les calculs de nombres entiers sont effectués, par exemple:

$ print $((1/3))  
0

Cela peut être utile lorsque vous avez besoin de mathématiques à virgule flottante dans un script shell, car vous pouvez éviter d'appeler une commande externe.

éternuements
la source
Il me semble que vous pourriez être intéressé à publier une réponse à Puis-je utiliser des fractions / décimales dans un script bash? Malgré le titre, je pense que le contexte montre clairement que d'autres coques de style Bourne sont pertinentes, c'est pourquoi j'ai posté une zshréponse . Depuis kshet bashsont plus semblables les uns aux autres (en général) que ce soit est à zsh, il me semble qu'une kh93réponse à cette question à base pourrait être très utile.
Eliah Kagan
1

letne fonctionne pas en cron. Je pense que cela est dû au fait d' letavoir son propre environnement. À utiliser $((...))puisque c'est POSIX. Par exemple,

let x=1+2
echo x=$x

dans cron, résulte en "x =", mais "x = 3" lorsqu'il est exécuté à partir du shell.

x=$((1+2))
echo x=$x

résulte dans "x = 3" dans tous les cas.

SparkEV
la source