78 votes

Test pour la chaîne vide avec X""

Je sais que je peux tester une chaîne vide en Bash avec -z comme ça :

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 ? S'agit-il simplement d'une erreur historique datant d'avant les jours 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 offert d'explication quant à por qué vous voyez du code avec le X"" truc.

1 votes

Excellente question. Ce post a une bonne réponse message d'erreur du serveur

124voto

Jonathan Leffler Points 299946

Fondamentalement, parce qu'en des temps maintenant révolus, le comportement de test était plus complexe et n'était pas définie de manière uniforme sur les différents systèmes (le code portable devait donc être écrit avec soin pour éviter les constructions non portables).

En particulier, avant test était un shell intégré, il s'agissait d'un exécutable séparé (et notez que MacOS X a toujours /bin/test y /bin/[ comme des exécutables). Lorsque c'était le cas, l'écriture :

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 et qu'il n'y avait donc rien à développer. Donc, la façon sûre d'écrire le code était :

if [ -z "$variable" ]

Cela fonctionne de manière fiable, en passant 4 arguments à la fonction test exécutable. Certes, le programme de test est intégré à la plupart des shells depuis des décennies, mais les vieux équipements ont la vie dure, tout comme 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 comprenaient des tirets en tête, ou contenaient des égaux ou d'autres comparateurs. Prenons un exemple qui n'est pas désespéré :

x="-z"
if [ $x -eq 0 ]

S'agit-il d'un test de chaîne vide avec un argument erroné, ou d'un test d'égalité numérique avec un premier argument non numérique ? Différents systèmes fournissaient des réponses différentes avant que POSIX ne standardise le comportement, vers 1990. Ainsi, la manière sûre de traiter ce problème était la suivante :

if [ "X$x" = "X0" ]

ou (moins souvent, d'après mon expérience, mais de manière tout à fait équivalente) :

if [ X"$x" = X"0" ]

Ce sont tous les cas limites comme celui-ci, liés à la possibilité que le test soit un exécutable séparé, qui signifient que le code shell portable utilise encore les guillemets doubles plus abondamment que ne le requièrent les shells modernes, et la notation du préfixe X a été utilisée pour s'assurer que les choses ne pouvaient pas être mal interprétées.

5 votes

La plupart des systèmes Unix-like, voire tous, ont encore des exécutables "test" et "[" (sur Ubuntu, ils sont dans /usr/bin, et non dans /bin). Cela leur permet d'être utilisés à partir d'autres choses que des scripts shell. (Consultez la documentation de votre système ; la commande est susceptible de se comporter de manière subtilement différente de l'interpréteur de commandes intégré -- qui lui-même peut varier d'un interpréteur de commandes à l'autre).

12voto

Diego Sevilla Points 17274

Ah, c'est l'une de mes questions et réponses préférées, car j'ai trouvé la réponse en y réfléchissant. Le site X est définie juste au cas où la chaîne de caractères commence par un caractère - qui peut être considéré comme un drapeau pour le test. En mettant un X avant ne fait que supprimer ce cas, et la comparaison peut toujours tenir.

J'aime aussi cela parce que ce genre d'astuce 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 qui existent (autoconf, configure, etc.).

1 votes

Ça a du sens... mais ça doit quand même être historique car myvar="-somval"; if [ -z $myvar ]; then echo "zero"; fi n'affiche pas "zéro" (ou autre dégueulis) sur mon shell (bash)...

1 votes

@mitch : oui, peut être qu'il n'échouera pas à exactement -z mais il est utilisé (par habitude, je pense) uniquement comme marqueur pour toutes les comparaisons de chaînes de caractères.

1 votes

Toutes les versions de test J'ai testé (bash intégré aussi) parser correctement les commandes comme [ -z = -z ] , [ ] != [ ] etc.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X