Je sais que je peux tester une chaîne vide dans Bash avec -z
ainsi:
if [[ -z $myvar ]]; then do_stuff; fi
mais je vois beaucoup de code écrit comme:
if [[ X"" = X"$myvar" ]]; then do_stuff; fi
Cette méthode est-elle plus portable? Est-ce juste une histoire historique d'avant l'époque de -z
? Est-ce pour les shells POSIX (même si je l’ai vu utilisé dans des scripts ciblant bash
)? Prêt pour ma leçon d'histoire/de portabilité.
La même question a été posée sur Server Fault en tant que Comment déterminer si une variable bash est vide? mais personne n’a donné d’explication quant à pourquoi vous voyez du code avec le X""
des trucs.
Fondamentalement, parce que jadis, le comportement de test
était plus complexe et non uniformément défini entre différents systèmes (le code portable devait donc être écrit avec soin pour éviter les constructions non portables).
En particulier, avant que test
soit un shell intégré, c’était un exécutable séparé (et notez que MacOS X a toujours /bin/test
et /bin/[
comme exécutables). Quand c'était le cas, écrivant:
if [ -z $variable ]
quand $variable
était vide invoquerait le programme de test via son alias [
avec 3 arguments:
argv[0] = "["
argv[1] = "-z"
argv[2] = "]"
parce que la variable était vide, il n'y avait donc rien à développer. Ainsi, le moyen le plus sûr d’écrire le code était:
if [ -z "$variable" ]
Cela fonctionne de manière fiable, en passant 4 arguments à l'exécutable test
. Certes, le programme de test est intégré à la plupart des réservoirs depuis des décennies, mais le vieil équipement a la vie dure, de même que les bonnes pratiques apprises il y a encore plus longtemps.
L'autre problème résolu par le préfixe X était ce qui se passait si les variables incluaient des tirets, des égaux ou d'autres comparateurs. Considérez (un exemple qui n'est pas désespérément bon):
x="-z"
if [ $x -eq 0 ]
S'agit-il d'un test de chaîne vide avec un argument parasite (erroné) ou d'un test d'égalité numérique avec un premier argument non numérique? Différents systèmes ont apporté différentes réponses avant que POSIX ait normalisé le comportement, vers 1990. Le moyen le plus sûr de traiter ce problème était le suivant:
if [ "X$x" = "X0" ]
ou (moins souvent, selon mon expérience, mais de manière tout à fait équivalente):
if [ X"$x" = X"0" ]
C'étaient tous les cas Edge comme celui-ci, liés à la possibilité que le test fût un exécutable séparé, ce qui signifie que le code shell portable utilise toujours les guillemets plus copieusement que les shells modernes ne l'exigent, et la notation du préfixe X a été utilisée pour veiller à ce que les choses ne puissent pas être mal interprétées.
Ah, c'est l'une de mes questions et réponses préférées, parce que j'ai trouvé la réponse juste pour y penser. Le X
est défini juste au cas où la chaîne commence par un -
, cela peut être considéré comme un indicateur pour le test. Mettre un X
avant juste supprime ce cas, et la comparaison peut toujours être vérifiée.
J'aime aussi ça parce que ce genre de tour est presque un héritage du passé, des temps les plus anciens de l'informatique, et vous le rencontrez lorsque vous essayez de lire certains des scripts Shell les plus portables (autoconf, configure, etc.)