Quelle est la différence entre les signes égaux simples et doubles (=) dans les comparaisons de shell?

28

Lisez que pour comparer les chaînes à l'intérieur, ifnous devons utiliser des crochets doubles. Certains livres disent que la comparaison peut être faite par =. Mais cela fonctionne aussi avec ==.

#!/bin/bash
a="hello"
b="world"
if [[ $a == $b ]];then
    echo "equal"
fi

Y a-t-il une différence entre =et ==dans la comparaison?

user3539
la source
4
Y a-t-il une question quelque part ici? Si c'est le cas, je ne le vois pas. =est pour [. ==est pour [[.
Chris Down
@ChrisDown Ce n'est absolument pas vrai.
xdavidliu
@xdavidliu Vous voulez élaborer? Il a certainement est vrai selon Posix, qui n'a pas de compréhension ==, ce qui est la raison pour laquelle vous devriez utiliser =(égalité) avec [, et ==(correspondance de motif, avec la sémantique qui sont en train de citer-aware) avec [[. Voir help testvs help [[.
Chris Down
@ChrisDown peut-être que je comprends mal ce que l'on entend par "est pour". Si "est pour" signifie "ne fonctionne qu'avec", alors le commentaire n'est pas vrai, car [ foo == foo ] && echo fooil s'imprime certainement foo, indiquant que cela ==fonctionne avec [. Cependant, si par "est pour" vous voulez dire "était destiné à être utilisé avec", alors j'ai une moindre objection.
xdavidliu
@xdavidliu "est pour" dans le cas spécifique dont vous parlez signifie "est défini par POSIX". Ce n'est pas parce que bash l'accepte comme commodité - si vous évitez la portabilité de toute façon, utilisez-le [[en premier lieu qui a une compréhension beaucoup plus nuancée de la tokenisation, du fractionnement de mots, etc ...
Chris Down

Réponses:

28

[[ $a == $b ]]n'est pas une comparaison, c'est une correspondance de motifs. Vous avez besoin [[ $a == "$b" ]]d'une comparaison d'égalité octet à octet. =est le même que== dans tout shell qui prend en charge [[...]](introduit par ksh).

[[...]]n'est pas une shsyntaxe standard . La [ commande est standard et l' opérateur de comparaison standard existe =(bien que certains[ implémentations le reconnaissent également ==).

Comme dans tout argument d'une commande, les variables doivent être citées, donc:

[ "$a" = "$b" ]

En standard sh, l'appariement des motifs se fait avec case:

case $a in
  ($b) ...
esac

Pour être complet, autre opérateurs de type égalité que vous pouvez rencontrer dans les scripts shell:

  • [ "$a" -eq "$b" ]: [opérateur standard pour comparer les nombres entiers décimaux. Certaines [implémentations autorisent des blancs autour des nombres, d'autres autorisent des expressions arithmétiques arbitraires, mais ce n'est pas portable. Portablement, on peut utiliser [ "$((a))" -eq "$((b))" ]pour cela. Voir aussi [ "$((a == b))" -ne 0 ]qui serait l'équivalent standard (sauf POSIXly, le comportement n'est spécifié que si$a et $bcontient des constantes entières) de:
  • ((a == b)), de ksh et également trouvé dans zsh et bash, renvoie vrai si l'évaluation de l'expression arithmétique stockée dans $adonne le même nombre que celle de $b. Généralement, c'est utilisé pour comparer les nombres. Notez qu'il existe des variations entre les shells quant à la façon dont les expressions arithmétiques sont évaluées et quels nombres sont pris en charge (par exemple bash et certaines implémentations / versions de ksh ne prennent pas en charge les virgules flottantes ou ne traitent pas les nombres avec des zéros de tête comme octaux).

  • expr "$a" = "$b"effectue une comparaison des nombres si les deux opérandes sont reconnus comme des nombres entiers décimaux (certains autorisant les espaces autour du nombre), et vérifie sinon si les deux opérateurs de chaîne ont le même ordre de tri. Il échouerait également pour les valeurs de $aou $bqui sont des expropérateurs comme (, substr...

  • awk 'BEGIN{exit !(ARGV[1] == ARGV[2])}' "$a" "$b": si $aet $bsont reconnus comme des nombres (au moins des nombres entiers décimaux et des nombres à virgule flottante comme 1.2, -1.5e-4, les blancs de début ignorés, certains reconnaissant également hexadécimal, octal ou tout ce qui est reconnu par strtod()), alors une comparaison numérique est effectuée. Sinon, selon l'implémentation, c'est soit une comparaison de chaîne octet à octet, soit comme pour exprune strcoll()comparaison, c'est-à-dire si $aet $btriez la même chose.

Voir également:

Stéphane Chazelas
la source
13

Ceux-ci sont équivalents en bash:

[[ $x == "$y" ]]
[[ $x = "$y" ]]
[ "$x" == "$y" ]
[ "$x" = "$y" ]

Les deux premières variables $ x n'ont pas besoin d'être citées. Bash effectue le fractionnement des mots et l'expansion des noms de chemin à l'intérieur de [mais pas à l'intérieur [[:

$ x='a b'
$ [ -s $x ]
-bash: [: a: binary operator expected
$ [[ -s $x ]]
$ ls
$ [ a = * ]
-bash: [: a: unary operator expected
$ [[ a = * ]]
$ 

[[ $x = "$y" ]]est une comparaison de chaînes mais [[ $x = $y ]]est une expression de correspondance de modèle:

$ y='a*'; [[ aa = "$y" ]]; echo $?
1
$ y='a*'; [[ aa = $y ]]; echo $?
0

-eq est uniquement destiné à être utilisé avec des entiers:

$ [[ x.x -eq x.x ]]
-bash: [[: x.x: syntax error: invalid arithmetic operator (error token is ".x")
$ x=9; [[ "x" -eq 9 ]]; echo $?
0

Voir aussi BashFAQ / 031: Quelle est la différence entre test, [et [[? .

Lri
la source