Le scripting bash est souvent déroutant. La syntaxe est parfois assez éloignée de ce à quoi nous sommes habitués dans d’autres langages. C’est d’ailleurs pourquoi beaucoup l’évitent au maximum. Pourtant, tôt ou tard, on a tous besoin d’écrire un petit .sh pour gérer un service ou automatiser un comportement sur un serveur.
Voilà pourquoi un petit rappel du fonctionnement des conditions – base de tout langage de programmation – en bash peut s’avérer salvateur. En route pour bashland !
Sous Linux et Unix, il existe plusieurs interpréteurs de commandes ou shell. Les fonctions supportées par l’un ou l’autre peuvent varier. Ainsi, nous parlons ici de bash, alias bourne again shell, le successeur de sh, le shell historique. Ce dernier est 100% compatible avec sh, en revanche, la réciproque n’est pas vraie. Nous verrons justement cela dans les conditions.
Anatomie d’un if
Prenons les choses dans l’ordre. En bash, point d’indentation ou d’accolades, un if
se démarque par des mots clefs de début et de fin.
Le if
teste uniquement le code de retour de la commande (0
étant le code de succès). Il est néanmoins souvent accompagné d’une commande de test.
Cette commande est test
, ou [
. Notez bien que contrairement aux langages de la famille C, les crochets []
utilisés pour les tests sont bien une commande et non une structure de langage.
Vous trouverez de plus amples explications à propos de test
sur Bash Hackers [en].
Évidemment, vous pouvez tout à fait omettre le elif
, le else
ou les deux. Vous pouvez également mettre plusieurs elif
les uns à la suite des autres.
Vous noterez bien que la condition est toujours entourée d’un espace après le crochet d’ouverture et avant le crochet de fermeture.
Dans les exemples ci-dessus, chaque mot clef est sur sa propre, ligne. Il est néanmoins possible de placer le then sur la même ligne que la condition en utilisant un point virgule.
Les syntaxes conditionnelles
Nous l’avons dit en introduction, bash est une évolution de sh. À ce titre, il comprend les conditions classique de sh, mais il intègre aussi une syntaxe plus avancée, laquelle n’est pas rétro-compatible. Voyons tout cela.
Conditions à simples crochets
Ce sont les conditions compatibles avec sh. Elles fonctionnent très bien dans la majorité des cas. On dénombre trois grandes familles de conditions : les conditions basées sur des fichiers ou dossier, celles basées sur des chaînes de caractères et enfin celles concernant des valeurs arithmétiques.
Conditions sur les fichiers
Permet de vérifier si un fichier ou un répertoire existe, sa nature etc. Nous verrons les différentes valeurs de conditions dans la suite de l’article.
Conditions sur les strings
Comme dans tous programme qui se respecte, on a toujours à traiter des chaînes de caractères.
Vous noterez qu’il n’y a qu’un signe égal pour la compatibilité POSIX. Le double, “==” fonctionne aussi. Mais il est suggéré d’utiliser le simple signe. Cela évitera des confusions.
Vous remarquez peut-être que la variable est entourée de guillemets. Bien que ce ne soit pas une obligation, ça vous évitera des bugs si elle contient des espaces ou des retours à la ligne par exemple. Par ailleurs, dans le cas de l’utilisation de test
, les guillemets sont obligatoires.
Conditions arithmétiques
On va ici comparer des entiers. Supérieur, inférieur, égal… la base quoi.
OR et AND
Il est possible d’utiliser le ET et le OU logique avec les simples crochets avec respectivement les arguments -o
et -a
.
Conditions à doubles crochets
Ces conditions permettent tout ce qu’offrent les conditions à simples crochets et plus. En revanche, elles ne sont pas compatibles avec sh. Elles prennent la forme suivante.
Ces conditions améliorées proposent l’usage du wildcard comme en bash ainsi que des expressions régulières. Ainsi, il est possible d’avoir des conditions comme cela :
On a donc accès aux expressions régulières, ce qui est assez confortable. En revanche, le caractère “*“ n’est pas interprété dans les conditions sur les fichiers.
Avec la syntaxe classique, la condition vaut true
s’il y a un fichier en .sh, false
s’il n’y en a pas, mais une erreur est retourné s’il y en a plusieurs…
La syntaxe améliorée permet aussi l’usage des opérateurs classiques de conditions tels que ||
et &&
. Par ailleurs, il est possible d’omettre les guillemets autour des variables car les espaces ne posent plus problème.
La syntaxe double parenthèses
Cette syntaxe dédiée aux comparaisons arithmétiques peut sembler plus familière car elle autorise les opérateurs plus connus dans d’autres langages : ==
, !=
, <
et >
. Elle supporte aussi les opérateurs &&
et ||
.
La syntaxe simplifiée
Au delà du test
et de la commande [ ]
, il est possible d’appliquer une condition sur le code de retour d’une commande.
Il est également possible de se passer du if
en utilisant la syntaxe double &&
. Cette instruction exécute la commande suivante si cette dernière retourne un code de succès.
Notez bien que dans le cas où vous utiliser la syntaxe simplifiée avec le ||
, la partie juste à droite – soit echo "ce fichier contient du php"
– doit toujours être vraie. Sans quoi le “ou” s’exécuterait aussi.
Table des conditions
Avant de vous laisser avec une petite liste de conditions, gardez toujours à l’esprit que les conditions possèdent toujours un espace entre les différents arguments. Ainsi, en bash 1 = 2
vaut false
, tandis que 1=2
vaut true
. Le =
sans espace est une assignation et non une comparaison !
On termine cet article en passant en revue les conditions les plus utiles.
Pour un aperçu exhaustif de toutes les possibilités, je vous laisse vous référer à The Linux Documentation Project.
Conditions sur les fichiers
Condition | Vrai si | Détails |
---|---|---|
[ -a fichier ] | “fichier” existe et est un fichier. | – |
[ -b blockspecialfile ] | Le fichier “blockspecialfile” existe et est de type block special. | Les block special files sont des fichiers qui représentent des périphériques, souvent des disques dur ou clefs USB. On les trouve principalement dans /dev ex. /dev/sda (disque a) et /dev/sda1 (partition 1 du disque a) |
[ -c characterspecialfile ] | Le fichier “characterspecialfile” existe et est de type caractère spécial. | Character special files sont des fichiers spéciaux du kernel, différents des block special files, ils ne sont pas mis en mémoire tampon, buffered, leur effet est immédiat : envoie du caractère au driver correspondant (émission d’un son via la carte son etc). Ce type de fichier concerne aussi les pseudo-devices /dev/null, /dev/zero, /dev/full, /dev/random et /dev/urandom. N’hésitez pas à jeter un œil à ce post Stackexchange pour plus de détails sur ces fichiers spéciaux |
[ -d dossier ] | dossier existe et est un dossier | – |
[ -e fichier ] | Même comportement que -a. | – |
[ -f fichier_normal ] | fichier_normal existe et est un fichier “normal”. | Par normal, on entend que le fichier n’est ni de type block, ni character special. |
[ -h lien_symbolique ] | lien_symbolique existe et est un lien symbolique | – |
[ -L lien_symbolique ] | Même comportement que -h. | |
[ -r fichier_lisible ] | fichier_lisible existe et est lisible du script | – |
[ -s fichier_non_vide ] | fichier_non_vide existe et possède une taille non nulle | – |
[ -w fichier_writable ] | fichier_writable existe et le script peut y écrire. | – |
[ -x executable ] | executable existe et est exécutable depuis le script | Concernant un répertoire, le droit d’exécution permet simplement de lister son contenu. |
Conditions sur les strings
Nous avons vu le plus complexe. En effet, Linux possède de nombreux types de fichiers et nous avons donc des conditions qui n’ont pas lieu d’exister dans tous les langages.
Les conditions sur les chaînes de caractères sont plus classiques. Les ==
et !=
se passent d’explications. <
et >
permettent de détermine si un string est avant un autre dans un classement par ordre alphabétique… oui ça peut servir, who knows.
Enfin, deux conditions un peu particulière permettent de savoir si un string est vide ou non : [ -n string_non_vide ]
et [ -z string_vide ]
.
Conditions sur les entiers
Nous l’avons vu, avec la syntaxe à double parenthèses, rien de sorcier, c’est comme nous en avons l’habitude dans tous les autres langages. En revanche, pour la syntaxe classique, avec les crochets, c’est un peu moins intuitif. Si vous connaissez MongoDB, c’est comme les conditions en Mongo.
[ nombre_1 -eq nombre_2 ]
pour equal, égal.[ nombre_1 -ne nombre_2 ]
pour not equal, non égal.[ nombre_1 -gt nombre_2 ]
pour greater than, plus grand que.[ nombre_1 -ge nombre_2 ]
pour greater than or equal, plus grand ou égal.[ nombre_1 -lt nombre_2 ]
pour less than, plus petit.[ nombre_1 -le nombre_2 ]
pour less than or equal.
Et voilà, nous avons là un bon condensé des possibilités offertes par les conditions en bash – et en shell sh. N’hésitez pas à apporter des pricisions/corrections ou à poser des questions en commentaires. Il ne vous reste plus qu’à coder. 3… 2… 1… #!/bin/bash
!