Comment savoir si une chaîne n’est pas définie dans un script shell bash?

Si je veux vérifier la chaîne vide, je le ferais

[ -z $mystr ] 

mais que faire si je veux vérifier si la variable a été définie? Ou n’y a-t-il pas de distinction dans les scripts bash?

Je pense que la réponse que vous recherchez est implicite (si elle n’est pas énoncée) par la réponse de Vinko , bien qu’elle ne soit pas expliquée simplement. Pour distinguer si VAR est défini mais vide ou non défini, vous pouvez utiliser:

 if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi if [ -z "$VAR" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi 

Vous pouvez probablement combiner les deux tests de la deuxième ligne en un seul avec:

 if [ -z "$VAR" -a "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi 

Cependant, si vous lisez la documentation d’Autoconf, vous constaterez qu’ils ne recommandent pas de combiner des termes avec -a et recommandent d’utiliser des tests simples séparés combinés à && . Je n’ai pas rencontré un système où il y a un problème; cela ne signifie pas qu’ils n’existaient pas (mais ils sont probablement extrêmement rares de nos jours, même s’ils n’étaient pas aussi rares dans le passé).

Vous pouvez trouver les détails de ces extensions , ainsi que d’autres extensions de parameters de shell associés, le test ou les [ commandes et expressions conditionnelles dans le manuel de Bash.


J’ai été récemment invité par email à répondre à cette question avec la question suivante:

Vous utilisez deux tests et je comprends bien le second mais pas le premier. Plus précisément, je ne comprends pas la nécessité d’une expansion variable

 if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi 

Est-ce que cela n’accomplirait pas la même chose?

 if [ -z "${VAR}" ]; then echo VAR is not set at all; fi 

Fair question – la réponse est “Non, votre solution plus simple ne fait pas la même chose”.

Supposons que j’écris ceci avant votre test:

 VAR= 

Votre test indiquera “VAR n’est pas défini du tout”, mais le mien dira (implicitement parce qu’il ne fait rien) “VAR est défini mais sa valeur peut être vide”. Essayez ce script:

 ( unset VAR if [ -z "${VAR+xxx}" ]; then echo JL:1 VAR is not set at all; fi if [ -z "${VAR}" ]; then echo MP:1 VAR is not set at all; fi VAR= if [ -z "${VAR+xxx}" ]; then echo JL:2 VAR is not set at all; fi if [ -z "${VAR}" ]; then echo MP:2 VAR is not set at all; fi ) 

La sortie est la suivante:

 JL:1 VAR is not set at all MP:1 VAR is not set at all MP:2 VAR is not set at all 

Dans la deuxième paire de tests, la variable est définie, mais elle est définie sur la valeur vide. C’est la distinction que font les notations ${VAR=value} et ${VAR:=value} . Idem pour ${VAR-value} et ${VAR:-value} , et ${VAR+value} et ${VAR:+value} , etc.


Comme le fait remarquer Gili dans sa réponse , si vous exécutez bash avec l’option set -o nounset , la réponse de base ci-dessus échoue avec la unbound variable . Il est facile d’y remédier:

 if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi if [ -z "${VAR-}" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi 

Ou vous pouvez annuler l’option set -o nounset avec set +u ( set -u étant équivalent à set -o nounset ).

 ~> if [ -z $FOO ]; then echo "EMPTY"; fi EMPTY ~> FOO="" ~> if [ -z $FOO ]; then echo "EMPTY"; fi EMPTY ~> FOO="a" ~> if [ -z $FOO ]; then echo "EMPTY"; fi ~> 

-z fonctionne également pour les variables non définies. Pour faire la distinction entre un non défini et un défini, utilisez les éléments répertoriés ici ou, avec des explications plus claires, ici .

La méthode la plus propre utilise l’expansion comme dans ces exemples. Pour obtenir toutes vos options, consultez la section Extension des parameters du manuel.

Mot alternatif:

 ~$ unset FOO ~$ if test ${FOO+defined}; then echo "DEFINED"; fi ~$ FOO="" ~$ if test ${FOO+defined}; then echo "DEFINED"; fi DEFINED 

Valeur par défaut:

 ~$ FOO="" ~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi ~$ unset FOO ~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi UNDEFINED 

Bien sûr, vous utiliseriez l’une de ces méthodes différemment, en mettant la valeur souhaitée au lieu de «valeur par défaut» et en utilisant directement l’extension, le cas échéant.

Guide de script avancé bash, 10.2. Paramètre Substitution:

  • $ {var + blahblah}: si var est défini, l’expression “blahblah” est substituée, sinon null est substitué
  • $ {var-blahblah}: si var est défini, il est lui-même substitué, sinon ‘blahblah’ est substitué
  • $ {var? blahblah}: si var est défini, il est substitué, sinon la fonction existe avec ‘blahblah’ comme message d’erreur.

Pour baser la logique de votre programme sur la définition ou non de la variable $ mystr, vous pouvez procéder comme suit:

 isdefined=0 ${mystr+ export isdefined=1} 

maintenant, si isdefined = 0 alors la variable était indéfinie, si isdefined = 1 la variable a été définie

Cette façon de vérifier les variables est meilleure que la réponse ci-dessus car elle est plus élégante, lisible et si votre shell bash a été configuré en erreur lors de l’utilisation de variables non définies (set -u) , le script se terminera prématurément.

Autres choses utiles:

avoir une valeur par défaut de 7 assignée à $ mystr si elle était indéfinie, et la laisser intacte sinon:

 mystr=${mystr- 7} 

pour imprimer un message d’erreur et quitter la fonction si la variable n’est pas définie:

 : ${mystr? not defined} 

Attention ici, j’ai utilisé ‘:’ pour ne pas que le contenu de $ mystr soit exécuté en tant que commande au cas où il serait défini.

Un résumé des tests.

 [ -n "$var" ] && echo "var is set and not empty" [ -z "$var" ] && echo "var is unset or empty" [ "${var+x}" = "x" ] && echo "var is set" # may or may not be empty [ -n "${var+x}" ] && echo "var is set" # may or may not be empty [ -z "${var+x}" ] && echo "var is unset" [ -z "${var-x}" ] && echo "var is set and empty" 

https://stackoverflow.com/a/9824943/14731 contient une meilleure réponse (celle qui est plus lisible et fonctionne avec set -o nounset activé). Cela fonctionne à peu près comme ceci:

 if [ -n "${VAR-}" ]; then echo "VAR is set and is not empty" elif [ "${VAR+DEFINED_BUT_EMPTY}" = "DEFINED_BUT_EMPTY" ]; then echo "VAR is set, but empty" else echo "VAR is not set" fi 

Le moyen explicite de vérifier une variable en cours de définition serait:

 [ -v mystr ] 

une autre option: l’extension “index tableau” :

 $ unset foo $ foo= $ echo ${!foo[*]} 0 $ foo=bar $ echo ${!foo[*]} 0 $ foo=(bar baz) $ echo ${!foo[*]} 0 1 

le seul moment où cette chaîne est vide est lorsque foo est désactivé, vous pouvez donc le vérifier avec la chaîne conditionnelle:

 $ unset foo $ [[ ${!foo[*]} ]]; echo $? 1 $ foo= $ [[ ${!foo[*]} ]]; echo $? 0 $ foo=bar $ [[ ${!foo[*]} ]]; echo $? 0 $ foo=(bar baz) $ [[ ${!foo[*]} ]]; echo $? 0 

devrait être disponible dans n’importe quelle version bash> = 3.0

ne pas jeter ce vélo encore plus loin, mais je voulais append

 shopt -s -o nounset 

est quelque chose que vous pouvez append en haut d’un script, ce qui entraînera une erreur si les variables ne sont déclarées nulle part dans le script. Le message que vous voyez est une unbound variable , mais comme d’autres le mentionnent, il n’acceptera pas une chaîne vide ou une valeur nulle. Pour vous assurer qu’aucune valeur individuelle n’est vide, nous pouvons tester une variable lorsqu’elle est développée avec ${mystr:?} , également connue sous le nom d’extension dollar sign, ce qui entraînerait une erreur avec le parameter null or not set .

Le manuel de référence de Bash est une source d’informations faisant autorité sur bash.

Voici un exemple de test d’une variable pour voir si elle existe:

 if [ -z "$PS1" ]; then echo This shell is not interactive else echo This shell is interactive fi 

(De la section 6.3.2 .)

Notez que les espaces après l’ouverture [ et avant le ] ne sont pas facultatifs .


Conseils pour les utilisateurs de Vim

J’ai eu un script qui comportait plusieurs déclarations comme suit:

 export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part" 

Mais je voulais qu’ils se réfèrent à toutes les valeurs existantes. Je les ai donc ré-écrits pour ressembler à ceci:

 if [ -z "$VARIABLE_NAME" ]; then export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part" fi 

J’ai pu automatiser cela en vim en utilisant une regex rapide:

 s/\vexport ([A-Z_]+)\=("[^"]+")\n/if [ -z "$\1" ]; then\r export \1=\2\rfi\r/gc 

Cela peut être appliqué en sélectionnant visuellement les lignes pertinentes, puis en tapant:. La barre de commandes est pré-remplie avec :'< ,'> . Collez la commande ci-dessus et appuyez sur Entrée.


Testé sur cette version de Vim:

 VIM - Vi IMproved 7.3 (2010 Aug 15, comstackd Aug 22 2015 15:38:58) Comstackd by root@apple.com 

Les utilisateurs Windows peuvent souhaiter des fins de ligne différentes.

Voici ce que je pense est une façon beaucoup plus claire de vérifier si une variable est définie:

 var_defined() { local var_name=$1 set | grep "^${var_name}=" 1>/dev/null return $? } 

Utilisez-le comme suit:

 if var_defined foo; then echo "foo is defined" else echo "foo is not defined" fi 

call set sans aucun argument .. il affiche tous les vars définis.
les derniers sur la liste seraient ceux définis dans votre script.
de sorte que vous pouvez canaliser sa sortie à quelque chose qui pourrait déterminer ce que les choses sont définies et ce qui ne sont pas