Un opérateur de comparaison binaire compare deux variables ou quantités. Remarque : les comparaisons d'entiers et les comparaisons de chaînes de caractères utilisent un ensemble d'opérateurs différent.
est égal à
if [ "$a" -eq "$b" ]
n'est pas égal à
if [ "$a" -ne "$b" ]
est supérieur à
if ["$a" -gt "$b" ]
est supérieur ou égal à
if [ "$a" -ge "$b" ]
est inférieur à
if [ "$a" -lt "$b" ]
est inférieur ou égal à
if [ "$a" -le "$b" ]
est inférieur à (entre doubles parenthèses)
(("$a" < "$b"))
est inférieur ou égal à (entre doubles parenthèses)
(("$a"< "$b"))
est supérieur à (dans une expression entre doubles-parenthèses)
(("$a" > "$b"))
est supérieur ou égal à (dans une expression entre doubles-parenthèses)
(("$a" >= "$b"))
comparaison de chaînes de caractères
est égal à
if [ "$a" = "$b" ]
Notez le blanc qui entoure le signe =.
if [ "$a"="$b" ] ne produit pas le même résultat.
est égal à
if [ "$a" == "$b" ]
Synonyme de =.
L'opérateur de comparaison == se comporte différemment à l'intérieur d'un test à double crochets et à l'intérieur de crochets simples.
[[ $a == z* ]] # Vrai si $a commence par 'z' # (correspondance d'expression rationnelle). [[ $a == "z*" ]] # Vrai si $a est égal à z* (égalité littérale). [ $a == z* ] # La correspondance de fichiers et la coupure de # mots pourront avoir lieu. [ "$a" == "z*" ] # Vrai si $a est égal à z* (égalité littérale). # Merci à Stéphane Chazelas
n'est pas égal à
if [ "$a" != "$b" ]
Cet opérateur utilise la reconnaissance de motifs à l'intérieur d'expressions en [[ ... ]].
est inférieur à, dans l'ordre alphabétique ASCII
if [[ "$a" < "$b" ]]
if [ "$a" \< "$b" ]
Notez que, s'il se trouve dans une expression en [ ], « < » doit être précédé d'un caractère d'échappement.
est supérieur à, dans l'ordre alphabétique ASCII
if [[ "$a" > "$b" ]]
if [ "$a" \> "$b" ]
Notez que, s'il se trouve dans une expression en [ ], « > » doit être précédé d'un caractère d'échappement.
Voir l'Exemple 27.10, « Le tri bulle : Bubble Sort » pour une application de cet opérateur de comparaison.
la chaîne de caractères est vide, c'est-à-dire qu'elle est de longueur nulle
Chaine='' # Variable chaîne de caractères de longueur nulle (vide). if [ -z "$Chaine" ] then echo "\$Chaine est vide." else echo "\$Chaine n'est PAS vide." fi # $Chaine est vide.
la chaîne de caractères n'est pas vide.
Attention : Le test -n exige que la chaîne de caractères soit entre guillemets à l'intérieur des crochets de test. Pour une chaîne sans guillemets, il faut utiliser l'option ! -z, ou encore laisser seule la chaîne à tester dans guillemets, (voir l'Exemple 7.6, « Vérifier si une chaîne est vide »), mais ce sont des pratiques risquées. Placez toujours vos chaînes de caractères à tester entre guillemets. [36]
Exemple 7.5. Comparaisons des nombres et des chaînes de caractères
#!/bin/bash a=4 b=5 # Ici, "a" et "b" peuvent être soit des entiers, soit des #+ chaînes de caractères. # Il y a un certain flou entre comparaisons arithmétiques et #+ comparaisons de chaînes car les variables Bash ne sont pas #+ fortement typées. # Bash permet les opérations prévues pour les entiers, et les # comparaisons, sur les variables qui contiennent uniquement des # caractères numériques. Néanmoins, il convient d'être prudent. echo if [ "$a" -ne "$b" ] then echo "$a n'est pas égal à $b" echo "(comparaison arithmétique)" fi echo if [ "$a" != "$b" ] then echo "$a n'est pas égal à $b." echo "(comparaison de chaînes de caractères)" # "4" != "5" # ASCII 52 != ASCII 53 fi # Dans ce cas précis, "-ne" et "!=" fonctionnent tous les deux. echo exit 0
Exemple 7.6. Vérifier si une chaîne est vide
#!/bin/bash # str-test.sh: Tester des chaînes vides sans guillemets, # "but not strings and sealing wax, not to mention cabbages and kings..." # (extrait de l'histoire des huîtres, dans "Alice au Pays des Merveilles") # Utilisation de if [ ... ] # Tant qu'une chaîne n'a pas été initialisée, elle n'a aucune valeur définie. # Cet état est appelé "vide" (en anglais "null", ce n'est pas la #+ même chose que zéro). if [ -n $chaine1 ] # $chaine1 n'a été ni déclarée ni initialisée. then echo "La chaîne \"chaine1\" n'est pas vide." else echo "La chaîne \"chaine1\" est vide." fi # Mauvais résultat. # Affiche $chaine1 comme non vide alors qu'elle n'a pas été initialisée. echo # Nouvel essai. if [ -n "$chaine1" ] # Cette fois, $chaine1 est entre guillemets. then echo "La chaîne \"chaine1\" n'est pas vide." else echo "La chaîne \"chaine1\" est vide." fi # Il faut échapper les chaînes à l'intérieur des crochets de test ! echo if [ $chaine1 ] # À présent, $chaine1 est toute seule. then echo "La chaîne \"chaine1\" n'est pas vide." else echo "La chaîne \"chaine1\" est vide." fi # Ça marche. # L'opérateur de test [ ] tout seul détecte que la chaîne est vide. # Néanmoins, il est de bonne pratique de mettre des guillemets ("$chaine1"). # # Comme dirait Stéphane Chazelas : # if [ $chaine1 ] a un seul argument, "]" # if [ "$chaine1" ] a deux arguments, la chaîne vide "$chaine1" et "]" echo chaine1=initialisée if [ $chaine1 ] # Cette fois encore, $chaine1 est sans guillemets. then echo "La chaîne \"chaine1\" n'est pas vide." else echo "La chaîne \"chaine1\" est vide." fi # De nouveau, on a le résultat correct. # Malgré tout, il vaut mieux mettre "$chaine1" entre guillemets, parce # que... chaine1="a = b" if [ $chaine1 ] # $chaine1 est encore sans guillemets. then echo "La chaîne \"chaine1\" n'est pas vide." else echo "La chaîne \"chaine1\" est vide." fi # Ne pas mettre "$chaine1" entre guillemets donne un résultat faux ! exit 0 # Merci également à Florian Wisser pour sa vigilance.
Exemple 7.7. zmore
#!/bin/bash # Lire les fichiers gzippés avec 'more' SANSARGS=65 PASTROUVE=66 NONGZIP=67 if [ $# -eq 0 ] # a le même effet que: if [ -z "$1" ] # $1 peut exister et être vide, comme dans : zmore "" arg2 arg3 then echo "Usage: `basename $0` nomfichier" >&2 # Message d'erreur vers stderr. exit $SANSARGS # Renvoie 65 comme code de sortie du script (code d'erreur). fi nomfichier=$1 if [ ! -f "$nomfichier" ] # Mettre $nomfichier entre guillemets permet d'avoir #+ des espaces dans les noms de fichiers. then echo "Fichier $nomfichier introuvable !" >&2 # Message d'erreur vers stderr. exit $PASTROUVE fi if [ ${nomfichier##*.} != "gz" ] # Utilisation d'accolades pour le développement des expressions" then echo "Le fichier $1 n'est pas une archive gzip !" exit $NONGZIP fi zcat $1 | more # Utilise le filtre 'more'. # Vous pouvez mettre 'less' à la place, si vous préférez. exit $? # Le script renvoie le code d'erreur de la commande tubée. # En fait, "exit $?" n'est pas nécessaire, car le script retournera #+ chaque fois le code de sortie de la dernière commande exécutée.
Ces options ressemblent beaucoup aux opérateurs de comparaison de Bash && et ||, utilisés à l'intérieur de doubles crochets.
[[ condition1 && condition2 ]]
Les opérateurs -o et -a fonctionnent avec la commande test ou à l'intérieur des crochets simples de test.
if [ "$expr1" -a "$expr2" ] then echo "expr1 and expr2 sont vraies toutes les deux" else echo "expr1 est fausse ou bien expr2 est fausse" fi
Cependant, comme le remarque rihad :
[ 1 -eq 1 ] && [ -n "`echo true 1>&2`" ] # vrai [ 1 -eq 2 ] && [ -n "`echo true 1>&2`" ] # (aucune sortie) # ^^^^^^^ La condition est fausse. Jusqu'ici, tout se passe comme prévu. # Mais ... [ 1 -eq 2 -a -n "`echo true 1>&2`" ] # vrai # ^^^^^^^ La condition est fausse. Alors, pourquoi cette sortie "true" ? # Est-ce parce que les deux clauses conditionnelles entre crochets s'évaluent ? [[ 1 -eq 2 && -n "`echo true 1>&2`" ]] # (aucune sortie) # Non, ce n'est pas cela. # Apparemment, && et || "court-circuitent" tandis que -a et -o ne le font pas.
Reportez-vous à l'Exemple 8.3, « Tests de conditions composées avec utilisation de && et de || », à l'Exemple 27.16, « Simuler un tableau à deux dimensions, puis son test » et à l'Exemple A.29, « Chasse aux spammeurs » pour voir à l'oeuvre les opérateurs de comparaison composée.
[36] Comme S.C. l'a relevé, dans un test composé, placer la variable chaîne de caractères entre guillemets peut ne même pas suffire. [ -n "$chaine" -o "$a" = "$b" ] peut provoquer une erreur avec certaines versions de Bash si $chaine est vide. La méthode la plus sûre est d'ajouter un caractère supplémentaire aux variables potentiellement vides, [ "x$chaine" != x -o "x$a" = "x$b" ] (les « x » s'annulent).