Pourquoi les comparaisons de scripts shell utilisent-elles souvent x $ VAR = xyes?

StackOverflow https://stackoverflow.com/questions/174119

  •  05-07-2019
  •  | 
  •  

Question

Je le vois souvent dans les scripts de construction des projets utilisant autotools (autoconf, automake). Lorsque quelqu'un veut vérifier la valeur d'une variable shell, il utilise fréquemment cet idiome:

if test "x$SHELL_VAR" = "xyes"; then
...

Quel est l'avantage de cela par rapport à la simple vérification de la valeur suivante:

if test $SHELL_VAR = "yes"; then
...

Je pense qu'il doit y avoir une raison pour laquelle je le vois si souvent, mais je ne peux pas comprendre ce que c'est.

Était-ce utile?

La solution

Si vous utilisez un shell qui effectue une simple substitution et que la variable SHELL_VAR n'existe pas (ou est vide), vous devez faire attention au bord cas. Les traductions suivantes se produiront:

if test $SHELL_VAR = yes; then        -->  if test = yes; then
if test x$SHELL_VAR = xyes; then      -->  if test x = xyes; then

Le premier d'entre eux générera une erreur car le premier argument de test a disparu. Le second n’a pas ce problème.

Votre cas se traduit comme suit:

if test "x$SHELL_VAR" = "xyes"; then  -->  if test "x" = "xyes"; then

Cela peut sembler un peu redondant, car il contient à la fois les guillemets et le "x". mais il gérera également une variable contenant des espaces, sans donner cela comme deux arguments à la commande test .

L'autre raison (autre que les variables vides) est liée au traitement des options. Si vous écrivez:

if test "$1" = "abc" ; then ...

et $ 1 a la valeur -n ou -z ou toute autre option valide de la commande test , la syntaxe est ambiguë. Le x à l'avant empêche la saisie d'un tiret en tête en tant qu'option pour tester .

N'oubliez pas que cela dépend du shell. Certains shells ( csh , je pense) se plaindront amèrement si la variable d'environnement n'existe pas plutôt que de simplement renvoyer une chaîne vide).

Autres conseils

L'autre raison pour laquelle personne d'autre n'a encore mentionné est liée au traitement des options. Si vous écrivez:

if [ "$1" = "abc" ]; then ...

et $ 1 a la valeur '-n', la syntaxe de la commande test est ambiguë; ce que vous testiez n'est pas clair. Le "x" à l'avant empêche un tiret de créer des problèmes.

Vous devez regarder de très vieux shell pour en trouver un où la commande test ne prend pas en charge -n ou -z ; la commande test de la version 7 (1978) les incluait. Ce n'est pas tout à fait hors de propos - certains éléments UNIX de la version 6 se sont échappés dans BSD, mais ces derniers temps, il serait extrêmement difficile de trouver quelque chose d'aussi ancien dans son utilisation actuelle.

Ne pas utiliser de guillemets autour des valeurs est dangereux, comme l'ont souligné d'autres personnes. En effet, s’il est possible que les noms de fichiers contiennent des espaces (MacOS X et Windows l’encouragent dans une certaine mesure, et Unix l’a toujours pris en charge, bien que des outils tels que xargs le rendent plus difficile), alors vous devriez: mettez également les noms de fichier entre guillemets chaque fois que vous les utilisez. Sauf si vous êtes responsable de la valeur (par exemple lors de la gestion des options et que vous définissez la variable sur "non" au démarrage et sur "oui" lorsqu'un indicateur est inclus dans la ligne de commande), il n'est pas prudent d'utiliser des formes de variable sans guillemets jusqu'à ce que vous les ayez prouvés en sécurité - et vous pouvez également le faire tout le temps pour de nombreuses raisons. Ou documentez que vos scripts vont échouer terriblement si les utilisateurs tentent de traiter des fichiers avec des noms vides. (Et il y a d'autres personnages à s'inquiéter aussi - les backticks pourraient être assez méchants aussi, par exemple.)

Il y a deux raisons que je connais pour cette convention:

http://tldp.org/LDP/abs/html/comparison- ops.html

  

Dans un test composé, même citer la variable chaîne pourrait ne pas suffire.   [-n " $ string " -o " $ a " = " $ b " ] peut provoquer une erreur avec certaines versions de   Bash si $ string est vide. La méthode la plus sûre consiste à ajouter un caractère supplémentaire à   éventuellement des variables vides, [" x $ string " ! = x -o " x $ a " = " x $ b " ] (les "x" et "annuler").

Deuxièmement, dans d’autres shells que Bash, en particulier les plus anciens, les conditions de test telles que '-z' pour tester une variable vide n’existaient pas. Ainsi:

if [ -z "$SOME_VAR" ]; then
  echo "this variable is not defined"
fi

fonctionnera bien dans BASH, si vous souhaitez la portabilité dans plusieurs environnements UNIX où vous ne pouvez pas être sûr que le shell par défaut sera Bash et s'il prend en charge la condition de test -z, il est plus sûr d'utiliser le formulaire. if [" x $ SOME_VAR " = " x " ] puisque cela aura toujours l'effet escompté. Il s’agit en réalité d’une vieille astuce de script shell pour trouver une variable vide. Elle est toujours utilisée aujourd’hui pour la compatibilité ascendante bien que des méthodes plus propres soient disponibles.

Je recommande plutôt:

if test "yes" = "$SHELL_VAR"; then

car il supprime le vilain x et résout le problème mentionné par https: // stackoverflow.com/a/174288/895245 que $ SHELL_VAR peut commencer par - et être lu en option.

Je crois que cela est dû à

SHELLVAR=$(true)
if test $SHELLVAR  = "yes" ; then echo "yep" ; fi 

# bash: test: =: unary operator expected

ainsi que

if test $UNDEFINEDED = "yes" ; then echo "yep" ; fi
# bash: test: =: unary operator expected

et

SHELLVAR=" hello" 
if test $SHELLVAR = "hello" ; then echo "yep" ; fi
# yep 

Cependant, cela devrait normalement fonctionner

SHELLVAR=" hello"
if test "$SHELLVAR" = "hello" ; then echo "yep" ; fi 
#<no output>

mais quand il se plaint ailleurs, il est difficile de dire de quoi il se plaint, alors

SHELLVAR=" hello"
if test "x$SHELLVAR" = "xhello" ; then echo "yep" ; fi 

fonctionne aussi bien, mais serait plus facile à déboguer.

Si vous ne faites pas le "x $ SHELL_VAR" Si $ SHELL_VAR n’est pas défini, vous obtenez une erreur à propos de " = " ne pas être un opérateur monadique ou quelque chose comme ça.

J'avais l'habitude de faire cela sous DOS lorsque SHELL_VAR pouvait être indéfini.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top