====== Bash : Les opérateurs de test sur chaînes ======
* Objet : Suite de la série de wiki visant à maîtriser bash via les caractères.
* Niveau requis : {{tag>débutant}}
* Commentaires : Bash, ligne de commande et scripts
* Débutant, à savoir : [[:doc:systeme:commandes:le_debianiste_qui_papillonne|Utiliser GNU/Linux en ligne de commande, tout commence là !.]] :-)
* Suivi : {{tag>à-tester}}
* Création par [[user>Hypathie]] le 08/04/2014
* Testé par [[user>Hypathie]] en Avril 2014
* Modifié par **agp91** le 21/02/2022
* Commentaires sur le forum : [[https://debian-facile.org/viewtopic.php?pid=140699#p140699 | Lien vers le forum concernant ce tuto]] ((N'hésitez pas à y faire part de vos remarques, succès, améliorations ou échecs !))
* [[doc:programmation:shells:bash-les-differents-caracteres-speciaux|Vision d'ensemble]]
* [[doc:programmation:shells:la-page-man-bash-les-caracteres-speciaux|Détail et caractères]]
* [[atelier:chantier:bash:les-operateurs-sur-parametres|Les opérateurs de test sur paramètres]]
* **Les opérateurs de test sur chaînes** ;-)
* [[atelier:chantier:bash:les-operateurs-de-test-sur-fichiers|Les opérateurs de test sur fichiers]]
* [[doc:programmation:shells:page-man-bash-iii-les-operateurs-de-comparaison-numerique|Les opérateurs de comparaison numérique]]
* [[doc:programmation:shells:page-man-bash-iv-symboles-dans-les-calculs-mathematiques|Les symboles dans les calculs]]
* [[doc:programmation:shells:page-man-bash-v-les-tableaux|Bash : les tableaux]]
* [[doc:programmation:shells:man-bash-vi-les-caracteres-de-transformation-de-parametres|Les caractères de transformation de parametres]]
* [[doc:programmation:shells:bash-vii-globs-etendus-regex|Bash : Variables, globs étendus, ERb, ERe]]
===== Introduction =====
Dans la page du manuel de bash, **les opérateurs des commandes de test** sont nommés __**primitives**__.
Bash dispose de plusieurs commandes pour **réaliser des tests sur des chaînes de caractères**.
* Les commandes internes **[** et **test**.
* Et la commande composée **[[**.
* Les commandes **[** et **test** sont équivalentes.
* Les commandes **[** et **test** sont disponibles dans leurs versions externe : **/usr/bin/[** et **/usr/bin/test**.
* Elles ont toutes les deux la même page de manuel (**man [** ou **man test**).
* Les commandes internes disposent de primitives que n'ont pas les commandes externes.
__Rappels :__
* Une commande de test renvoie le code de retour 0 (considéré comme vrai) lorsque le test réussi et 1 (considéreé comme faux) lorsqu'il échoue.
* Le code retour d'une commande est mémorisé dans le paramètre spécial $?.
* L'opérateur de contrôle **&&** exécute la commande suivante, si la commande précédente à renvoyée un code de retour égale à 0.
* L'opérateur de contrôle **||** exécute la commande suivante, si la commande précédente à renvoyée un code de retour supérieur à 0.
===== Tester une chaîne (vide ou pas) =====
Les commandes de test disposent de deux opérateurs unaires pour tester si une chaîne est vide (de longueur nulle) ou pas.
==== Syntaxe ====
* **test OP** [**"**]**chaîne**[**"**]
* **[ OP** [**"**]**chaîne**[**"**] **]**
* **[[ OP** [**"**]**chaîne**[**"**] **]]**
* Avec :
* **Chaîne** est sujette au développement des paramètres.
* **OP**, l'une des primitives du tableau suivant.
| Liste des primitives de test sur chaîne ||
^ Primitives ^ Retours ^
|''-z'' | Vrai si chaîne de longueur nulle |
|''-n'' | Vrai si chaîne de longueur non nulle |
* Si l'opérande (**chaîne**) contient des espaces, il doit être protégé.
* La primitive **-n** peut-être omis.
==== Exemples ====
test -z ; echo $? #Test si vide et affiche le code retour
[ -n "" ] ; echo $? #Test si non vide et affiche le code retour
[[ "" ]] ; echo $? #Test si non vide et affiche le code retour
0
1
1
test -z "mot" ; echo $?
[[ -n "Linux" ]] ; echo $?
[[ "GNU Linux" ]] ; echo $?
1
0
0
v="Debian GNU Linux"
test -z "$v" ; echo $?
v=""
[ -n "$v" ] ; echo $?
unset v # Supprime le paramètre v
[[ -z "$v" ]] ; echo $?
[ "$v" ] ; echo $?
1
0
0
1
==== Mauvais usages ====
Les directives **-z** et **-n** sont des directives unaires, elles n'acceptent qu'un seul opérande (argument).\\
Si sa valeur contient des espaces, il doit être protégé par des guillemets simple ou doubles.\\
__Rappel__ : Les guillemets simple ne permettent le remplacement des paramètres.
p="Debian Facile"
test -z $p ; echo $?
unset p
bash: test: Debian : opérateur binaire attendu
2
Lorsqu'une commande interne renvoie un **code de retour 2**, cela signifie un mauvais usage de cette commande.
La directive **-n** revoie un code de retour inattendu, quand un paramètre vide est testé sans protection.\\
Sauf avec la commande **[[**.
test -n $p ; echo $?
[ -n $p ] ; echo $?
p=""
[[ -n $p ]] ; echo $?
unset p
0
0
1
==== Astuces ====
Avec la directive **-z**, nous pouvons nous affranchir de la protection des guillemets en utilisant __le remplacement des paramètres__ et l'opérateur **+**.\\
(Voir [[https://debian-facile.org/doc:programmation:shells:man-bash-vi-les-caracteres-de-transformation-de-parametres#substitution-par-modification|Substitution de la valeur d'un paramètre]])
p="Debian GNU Linux"
test -z ${p+x} ; echo $?
unset p
[[ -z ${p+x} ]] ; echo $?
1
0
Lors du remplacement d'un paramètre, l’opérateur **+** permet, si la valeur du paramètre est non nulle, de la substituée par une autre valeur (ici **x**).
Avec la directive **-n** les guillemets restent nécessaires au cas ou le paramètre mémorise une chaîne vide, sauf avec la commande **[[**.
p="Debian Facile"
[[ -n ${p+x} ]] ; echo $?
[[ ${p+x} ]] ; echo $?
unset p
[[ -n ${p+x} ]] ; echo $?
[[ ${p+x} ]] ; echo $?
0
0
1
1
===== Comparaison entre deux chaînes =====
Les commandes de test disposent de 5 primitives binaires pour comparer deux chaînes entre elles.
==== Syntaxe ====
* **test chaîne1 OP chaîne2**
* **[ chaîne1 OP chaîne2 ]**
* **[[ chaîne1 OP chaîne2 ]]**
* Avec :
* **Chaîne1** et **chaîne2** sont sujettes au développement des paramètres.
* **OP**, l'un des opérateur du tableau suivant.
Si un opérande (**chaîne1** ou **chaîne**2) est une chaîne vide, ou contient des espaces,\\
Il doit être protégé, placé entre guillemets simples ou doubles.
| Listes des primitives de comparaison entre deux chaînes ||
^ Primitives ^ Retours ^
| ''= '' | Vrai si **Chaîne1** correspond à **Chaîne2** . |
| ''=='' | Synonyme de **=** |
| ''!='' | Vrai si **Chaîne1** ne correspond pas à **Chaîne2**. |
| ''<'' | Vrai si **chaine1** est placée lexicographiquement avant **chaine2** |
| ''>'' | Vrai si **chaine1** est placée lexicographiquement après **chaine2** |
==== Exemples ====
__-bashismes :__
[[ $a == "z*" ]] # vrai si $a est égal à z*
[[ $a == z* ]] # vrai si $a commence avec un "z" (reconnaissance de modèles)
[[ "$a" < "$b" ]] # vrai si $a se trouve avant $b dans le dictionnaire
__-posix :__
[ "$a" = "z*" ] # vrai si $a est égal à z*
[ "$a" \< "$b" ] # vrai si $a se trouve avant $b dans le dictionnaire
test "GNU" == "GNU" ] ; echo $?
[[ "GNU" != "GNU Linux" ]] ; echo $?
0
0
>Donc la chaîne "GNU" est identique à elle-même ;), mais pas à "GNU Linux".
v1="Debian GNU Linux"
v2="Debian Facile"
if [ "$v1" = "$v2" ]
then
echo 'vrai'
else
echo 'faux'
fi
unset v1 v2
faux
>Donc les deux chaînes contenues dans les variables v1 et v2 ne sont pas égales.
Copions le code suivant dans le fichier **mon_script**.
#!/bin/bash
var1="def"
var2="def"
if [ "$var1" == "$var2" ] ; then
echo "1) \$var1 ($var1) correspond(==) à \$var2 ($var2)."
fi
var3="hip"
var4="hip"
if test "$var3" = "$var4" ; then
echo "2) \$var3 ($var3) correspond(=) à \$var4 ($var4)."
fi
bash mon_script
rm -v mon_script
1) $var1 (def) correspond(==) à $var2 (def).
2) $var3 (hip) correspond(=) à $var4 (hip).
'mon_script' supprimé
Les commandes de test permettent de réaliser des test de comparaison lexicographique.\\
(voir [[https://debian-facile.org/atelier:chantier:bash-comparaison-lexicographique-des-chaines|https://debian-facile.org/atelier:chantier:bash-comparaison-lexicographique-des-chaines]].)
Attention de ne pas confondre les primitives de comparaison lexicographique sur les chaînes avec les [[https://debian-facile.org/doc:programmation:shells:page-man-bash-iii-les-operateurs-de-comparaison-numerique#operateurs-booleens-de-comparaison-numerique|opérateurs de comparaison numérique]] qui utilisent les mêmes caractères.
a="sloiuy"
b="aktgjaùkjayaj"
if [[ $a < $b ]] ; then
echo "OK l'opérateur < fonctionne avec les chaînes de caractère"
fi
if [[ $a > $b ]] ; then
echo "Les opérateurs < et > signifient avant et après selon l'ordre alphabétique (doubles crochets) "
fi
if [ $a \> $b ] ; then
echo "Les opérateurs \< et \> signifient avant et après selon l'ordre alphabétique (simples crochets) "
fi
OK L'opérateur < fonctionne avec les chaînes de caractère
Les opérateurs < et > signifient avant et après selon l'ordre alphabétique (doubles crochets)
Les opérateurs \< et \> signifient avant et après selon l'ordre alphabétique (simples crochets)
Avec les commandes **[** ou **test**, les primitives **<** et **>** doivent être protégées.\\
(Voir [[https://debian-facile.org/atelier:chantier:bash-comparaison-lexicographique-des-chaines#tests-avec1|Comparaison lexicographique avec [ ou test.]])
==== Mauvais usages ====
Les deux opérandes sont obligatoires.
test GNU == ; echo $?
[[ != LINUX ]]
echo $?
bash: test: GNU : opérateur unaire attendu
2
bash: opérateur binaire conditionnel attendu
bash: erreur de syntaxe près de « LINUX »
2
Les espaces entre les opérandes et la primitive sont obligatoires.
[ "GNU Linux"=="LINUX" ] ; echo $?
0
Sans espace entre les opérande et la primitive "GNU Linux"=="LINUX" est compris comme une chaîne de caractère.\\
N'étant pas nulle, le test n'échoue pas.
=====Tuto précédent =====
[[atelier:chantier:bash:les-operateurs-sur-parametres|Bash : Les opérateurs de test sur paramètres]]
=====La suite c'est ici =====
[[atelier:chantier:bash:les-operateurs-de-test-sur-fichiers|Les opérateurs de test sur fichiers]]