Comparaison d'entiers: expression arithmétique ou expression conditionnelle


20

Dans Bash, deux entiers peuvent être comparés à l'aide d'une expression conditionnelle

arg1 OP arg2

OP est l' un -eq, -ne, -lt, -le, -gtou -ge. Ces opérateurs binaires arithmétiques renvoient true si arg1 est respectivement égal, différent de, inférieur, inférieur ou égal, supérieur ou supérieur ou égal à arg2 . Arg1 et arg2 peuvent être des entiers positifs ou négatifs.

ou expression arithmétique:

<= >= < > Comparaison

== != égalité et inégalité

Pourquoi avons-nous deux façons différentes de comparer deux entiers? Quand utiliser quoi?

Par exemple, [[ 3 -lt 2 ]]utilise une expression conditionnelle et une (( 3 < 2 ))expression arithmétique. Les deux renvoient 0 lorsque la comparaison est vraie

Lors de la comparaison de deux nombres entiers, ces deux méthodes peuvent-elles toujours être utilisées de manière interchangeable? Si oui, pourquoi Bash a-t-il deux méthodes plutôt qu'une?


1
= != < <= > >=comparer les chaînes . 1 -eq 01mais 1 != 01et 8 -lt 42mais8 > 42
dave_thompson_085

Ils sont surchargés dans les expressions arithmétiques.
Tim

1
vous devrez rechercher dans les journaux des modifications de bash pour savoir quand chaque fonctionnalité a été ajoutée. Je soupçonne que les expressions arithmétiques ont été ajoutées bien plus tard que la commande de test.
glenn jackman

Je ne demande pas de comparer des chaînes. @muru.
Tim

Réponses:


28

Oui, nous avons deux façons différentes de comparer deux entiers.

Il semble que ces faits ne soient pas largement acceptés dans ce forum:

  1. A l' intérieur du langage [ ]les opérateurs de comparaison arithmétique sont -eq, -ne, -lt, -le, -gtet -ge.

    Comme ils sont également à l'intérieur d'une commande de test et à l'intérieur d'un [[ ]].

    Oui dans ce idiomes, =, <, etc. sont des opérateurs de chaîne.

  2. A l' intérieur du langage (( ))les opérateurs de comparaison arithmétique sont ==, !=, <, <=, >et >=.

    Non, ce n'est pas une "expansion arithmétique" (qui commence par a $) comme $(( )). Il est défini comme une "commande composée" dans man bash.

    Oui, il suit les mêmes règles (internes) de "l'expansion arithmétique" mais n'a pas de sortie, seulement une valeur de sortie. Il pourrait être utilisé comme ceci:

if (( 2 > 1 )); then ...

Pourquoi avons-nous deux façons différentes de comparer deux entiers?

Je suppose que ce dernier a (( ))été développé comme un moyen plus simple d'effectuer des tests arithmétiques. C'est presque le même que le $(( ))mais n'a juste aucune sortie.

Pourquoi deux? Eh bien la même chose que la raison pour laquelle nous avons deux printf(externes et builtin) ou quatre essais (externe test, builtin test, [et [[). C'est ainsi que les coquilles se développent, améliorant une zone en un an, en améliorant une autre l'année suivante.

Quand utiliser quoi?

C'est une question très difficile car il ne devrait pas y avoir de différence effective. Bien sûr, il y a quelques différences dans la façon dont une [ ]œuvre et une (( ))œuvre en interne, mais: laquelle vaut mieux comparer deux entiers? N'importe qui!.

Lors de la comparaison de deux nombres entiers, ces deux méthodes peuvent-elles toujours être utilisées de manière interchangeable?

Pour deux chiffres, je suis obligé de dire oui.
Mais pour les variables, les extensions, les opérations mathématiques, il peut y avoir des différences clés qui devraient favoriser l'une ou l'autre. Je ne peux pas dire que les deux sont absolument égaux. D'une part, le (( ))pourrait effectuer plusieurs opérations mathématiques en séquence:

if (( a=1, b=2, c=a+b*b )); then echo "$c"; fi

Si oui, pourquoi Bash a-t-il deux méthodes plutôt qu'une?

Si les deux sont utiles, pourquoi pas?.


1
=est une affectation et ==une comparaison dans les extensions arithmétiques. La question le cite correctement. Mais la réponse est fausse.
ceving

12

Historiquement, la testcommande a existé en premier (au moins aussi loin que Unix Seventh Edition en 1979). Il a utilisé les opérateurs =et !=pour comparer des chaînes, et -eq, -ne, -lt, etc. , pour comparer les chiffres. Par exemple, test 0 = 00est faux, mais test 0 -eq 00vrai. Je ne sais pas pourquoi cette syntaxe a été choisie, mais c'était peut-être pour éviter d'utiliser <and >, que le shell aurait analysé en tant qu'opérateurs de redirection. La testcommande a obtenu une autre syntaxe quelques années plus tard: [ … ]équivaut à test ….

La [[ … ]]syntaxe conditionnelle, à l'intérieur de laquelle <et >peut être utilisée comme opérateur sans guillemet, a été ajoutée plus tard, dans ksh. Il a conservé la compatibilité descendante avec [ … ], donc il a utilisé les mêmes opérateurs, mais a ajouté <et >pour comparer des chaînes (par exemple, [[ 9 > 10 ]]mais [[ 9 -lt 10 ]]). Pour plus d'informations, voir Utilisation d'un support simple ou double - bash

Les expressions arithmétiques sont également venues plus tard que la testcommande, dans le shell Korn , à un moment donné dans les années 1980. Ils ont suivi la syntaxe du langage C, qui était très populaire dans les cercles Unix. Ils ont donc utilisé les opérateurs de C: ==pour l'égalité, <=pour le plus ou moins, etc.

Unix Seventh Edition n'avait pas d'expressions arithmétiques, mais il avait la exprcommande , qui implémentait également une syntaxe de type C pour les opérations entières, y compris ses opérateurs de comparaison. Dans un script shell, les caractères <et >devaient être cités pour les protéger du shell, par exemple if expr 1 \< 2; …est équivalent à if test 1 -lt 2; …. L'ajout d'expressions arithmétiques au shell a rendu la plupart des utilisations exprobsolètes, donc ce n'est pas bien connu aujourd'hui.

Dans un script sh, vous utiliseriez généralement des expressions arithmétiques pour calculer une valeur entière et [ … ]comparer des nombres entiers.

if [ "$((x + y))" -lt "$z" ]; then 

Dans un script ksh, bash ou zsh, vous pouvez utiliser les ((…))deux.

if ((x + y < z)); then 

Le [[ … ]]formulaire est utile si vous souhaitez utiliser des conditions impliquant d'autres choses que des entiers.


1

Selon la page de manuel de test, = et! = Sont utilisés pour les comparaisons de chaînes tandis que les expressions -eq, -gt, -lt, -ge, -le et -ne sont des comparaisons entières. J'ai toujours suivi cette convention lors de l'écriture de scripts shell et cela fonctionne toujours. Sachez que si vous avez des variables dans l'expression, vous devrez peut-être citer les variables d'une manière ou d'une autre pour éviter de faire une comparaison nulle.

Sur papier, nous faisons des comparaisons chaîne / nombre sans trop y penser. Un ordinateur d'autre part ne sait pas si 987 est un nombre ou une chaîne de caractères. Vous avez besoin des différents opérateurs pour dire à l'ordinateur ce qu'il faut faire pour obtenir le bon résultat. Il y a quelques informations supplémentaires ici qui expliquent une partie de l'histoire. Essentiellement, les variables ne sont pas typées et sont restées ainsi pour la compatibilité historique.


Dans mon post, = et !=sont des opérateurs arithmétiques, alors que la page de manuel testmontre seulement des opérateurs d'expression conditionnelle.
Tim
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.