137 votes

Test si une variable est définie dans bash lors de l'utilisation de "set -o nounset".

Le code suivant se termine par une erreur de variable non liée. Comment résoudre ce problème, tout en continuant à utiliser le set -o option de nounset ?

#!/bin/bash

set -o nounset

if [ ! -z ${WHATEVER} ];
 then echo "yo"
fi

echo "whatever"

138voto

Angelom Points 1099
#!/bin/bash

set -o nounset

VALUE=${WHATEVER:-}

if [ ! -z ${VALUE} ];
 then echo "yo"
fi

echo "whatever"

Dans ce cas, VALUE finit par être une chaîne vide si WHATEVER n'est pas réglé. Nous utilisons le {parameter:-word} que vous pouvez consulter dans man bash sous "Expansion des paramètres".

23 votes

Remplacez simplement if [ ! -z ${VALUE} ] ; par if [ ! -z ${WHATEVER:-} ] ;

21 votes

:- vérifie si la variable est désactivée o vide. Si vous voulez vérifier sólo s'il n'est pas défini, utilisez - : VALUE=${WHATEVER-} . De plus, une façon plus lisible de vérifier si une variable est vide : if [ "${WHATEVER+defined}" = defined ]; then echo defined; else echo undefined; fi

1 votes

En outre, cela ne fonctionnera pas si $WHATEVER ne contient que des espaces blancs - Voir ma réponse.

39voto

l0b0 Points 10719

Vous devez citer les variables si vous voulez obtenir le résultat escompté :

check() {
    if [ -n "${WHATEVER-}" ]
    then
        echo 'not empty'
    elif [ "${WHATEVER+defined}" = defined ]
    then
        echo 'empty but defined'
    else
        echo 'unset'
    fi
}

Test :

$ unset WHATEVER
$ check
unset
$ WHATEVER=
$ check
empty but defined
$ WHATEVER='   '
$ check
not empty

0 votes

J'ai essayé et je suis surpris que cela fonctionne... Tout est correct sauf que selon "info bash" , "${WHATEVER-}" devrait avoir un ":" (deux points) avant le "-" (tiret) comme : "${WHATEVER:-}" et "${WHATEVER+defined}" doit être précédé de deux points. "+" (plus) comme : "${WHATEVER:+defined}" . Pour moi, cela fonctionne dans les deux sens, avec ou sans les deux-points. Sur certaines versions de 'nix, cela ne fonctionnera probablement pas sans inclure les deux-points, donc il faudrait probablement les ajouter.

10 votes

Non, - , + , :+ et :- sont toutes prises en charge. Les premiers détectent si la variable est set et la seconde détecte si elle est set o vide . De man bash : "L'omission des deux points entraîne un test uniquement pour un paramètre qui n'est pas défini."

2 votes

Nevermind =). Vous avez raison. Je ne sais pas comment j'ai pu manquer ça.

13voto

A-B-B Points 797

Hypothèses :

$ echo $SHELL
/bin/bash
$ /bin/bash --version | head -1
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
$ set -o nounset

Si vous voulez qu'un script non interactif imprime une erreur et sorte si une variable est nulle ou non définie :

$ [[ "${HOME:?}" ]]

$ [[ "${IAMUNBOUND:?}" ]]
bash: IAMUNBOUND: parameter null or not set

$ IAMNULL=""
$ [[ "${IAMNULL:?}" ]]
bash: IAMNULL: parameter null or not set

Si vous ne voulez pas que le script sorte :

$ [[ "${HOME:-}" ]] || echo "Parameter null or not set."

$ [[ "${IAMUNBOUND:-}" ]] || echo "Parameter null or not set."
Parameter null or not set.

$ IAMNULL=""
$ [[ "${IAMUNNULL:-}" ]] || echo "Parameter null or not set."
Parameter null or not set.

Vous pouvez même utiliser [ y ] au lieu de [[ y ]] ci-dessus, mais cette dernière est préférable dans Bash.

Notez ce que font les deux points ci-dessus. De la docs :

En d'autres termes, si les deux points sont inclus, l'opérateur vérifie à la fois l'existence du paramètre et le fait que sa valeur n'est pas nulle ; si les deux points sont omis, l'opérateur vérifie uniquement l'existence.

Il n'y a apparemment pas besoin de -n o -z .

En résumé, je peux typiquement utiliser [[ "${VAR:?}" ]] . Dans les exemples, cela affiche une erreur et quitte si une variable est nulle ou non définie.

12voto

NublaII Points 41

Que diriez-vous d'un oneliner ?

[ -z "${VAR:-}" ] && echo "VAR is not set or is empty" || echo "VAR is set to $VAR"

-z vérifie à la fois les variables vides ou non définies

2 votes

Non, -z vérifie uniquement si le paramètre suivant est vide. -z est juste un argument de la [ commande. L'expansion de la variable se produit avant [ -z peut faire n'importe quoi.

1 votes

Cela semble être la bonne solution, dans la mesure où elle ne génère pas d'erreur si $VAR n'est pas défini. @dolmen pouvez-vous fournir un exemple de cas où cela ne fonctionnerait pas ?

0 votes

@dolmen ayant lu diverses ressources bash sur l'expansion des paramètres et trouvant les autres réponses trop compliquées, je ne vois rien de mal dans celle-ci. Donc votre "clarification", bien que techniquement correcte, semble plutôt inutile en pratique, à moins que vous ayez besoin de différencier unset vs empty. J'ai testé unset, empty et non-empty, (bash 4) et il a fait à peu près ce qui est annoncé à chaque fois.

7voto

Aleš Friedl Points 1

Vous pouvez utiliser

if [[ ${WHATEVER:+$WHATEVER} ]]; then

mais

if [[ "${WHATEVER:+isset}" == "isset" ]]; then

pourrait être plus lisible.

0 votes

Les comparaisons de chaînes doivent utiliser la norme (POSIX) = opérateur, et non == pour faciliter la portabilité, et [ au lieu de [[ si possible.

3 votes

@Jens La question est spécifique à bash et comprend set -o nounset qui est spécifique à bash. Si vous mettez un #!/bin/bash en haut de votre script, il est en fait préférable d'utiliser les améliorations de bash.

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