Comment dire si une chaîne de caractères n'est pas définie dans un script shell bash?

si je veux vérifier la chaîne null je ferais

[ -z $mystr ]

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

138
demandé sur Mark Biek 2008-10-23 08:26:49

11 réponses

je pense que la réponse que vous êtes après est implicite (si non indiqué) par Vinko 's réponse , bien qu'il ne soit pas énoncé simplement. Pour distinguer si VAR est défini mais vide ou non, 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 sur 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 pour Autoconf, vous constaterez qu'ils font ne recommande pas de combiner les termes avec -a et recommande d'utiliser des tests simples séparés combinés avec && . Je n'ai pas rencontré de système où il y a un problème; cela ne veut pas dire qu'ils n'existaient pas auparavant (mais ils sont probablement extrêmement rares de nos jours, même s'ils n'étaient pas aussi rares dans un passé lointain).

vous pouvez trouver les détails de ces, et d'autres shell paramètres expansions , le test ou [ commande et expressions conditionnelles dans le manuel de Bash.


on m'a récemment demandé par courriel à propos de cette réponse avec la question:

Vous utilisez les deux tests, et je comprends le second mais pas le premier. Plus précisément, je ne comprends pas le besoin d'expansion variable

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

ne Serait-ce pas accomplir la même?

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

question correcte - la réponse est "non, votre alternative plus simple ne fait pas la même chose".

supposons que j'écrive ceci avant votre test:

VAR=

votre test dira "VAR n'est pas réglé du tout", mais le mien dira (implicitement parce qu'il ne fait écho à rien) "VAR est réglé mais sa valeur pourrait ê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
)

le sortie:

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 d'essais, la variable est définie, mais elle est définie à 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} , et ainsi de suite.


comme Gili souligne dans son réponse , si vous courez bash avec l'option set -o nounset , puis la réponse de base ci-dessus échoue avec unbound variable . Il est facilement remédié:

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 ).

128
répondu Jonathan Leffler 2017-05-23 12:17:59
~> 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 aussi pour les variables non définies. Pour distinguer entre un non défini et un défini, vous utiliseriez les choses énumérées ici ou, avec des explications plus claires, ici .

Cleanest way utilise l'expansion comme dans ces exemples. Pour obtenir toutes vos options, consultez la section expansion des paramètres 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 utiliserez l'un d'eux différemment, en mettant la valeur que vous voulez au lieu de la valeur par défaut et en utilisant l'extension directement, si approprié.

33
répondu Vinko Vrsalovic 2008-10-23 05:03:24

Advanced bash scripting guide, 10.2. Substitution De Paramètre:

  • ${var+blahblah}: si var est défini, 'blahblah' est remplacé par expression, sinon null est substitué
  • ${var-blahblah}: si var est défini, il est lui-même substitué, sinon
  • $ {var?blahblah}: si var est défini, il est substitué, sinon le fonction existe avec' blahblah ' comme message d'erreur.



pour baser votre logique de programme sur le fait que la variable $mystr est définie ou non, vous pouvez faire ce qui suit:

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

maintenant, si isdefined=0 alors la variable n'était pas définie, si isdefined=1 la variable était définie

cette façon de vérifier les variables est meilleure que la réponse ci-dessus parce qu'elle est plus élégante, lisible, et si votre shell bash a été configuré pour faire une erreur sur l'utilisation de variables non définies (set -u) , le script se terminera prématurément.



autres choses utiles:

pour avoir une valeur par défaut de 7 assignée à $mystr si elle n'était pas dé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 que je utilisé': 'afin de ne pas avoir le contenu de $mystr exécuté comme une commande au cas où il serait défini.

17
répondu 2012-05-13 20:28:25

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"
8
répondu k107 2012-06-09 23:29:36

https://stackoverflow.com/a/9824943/14731 contient une meilleure réponse (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
5
répondu Gili 2017-05-23 12:02:42

la façon explicite de vérifier si une variable est définie serait:

[ -v mystr ]
4
répondu Felix Leipold 2013-06-05 18:06:04

une autre option: le" tableau des indices de liste "expansion :

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

le seul moment où cette extension vers la chaîne vide est quand foo est désactivé, donc vous pouvez 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 de bash > = 3.0

1
répondu Aaron Davies 2012-03-27 22:23:47

ne pas jeter ce vélo encore plus loin, mais a voulu ajouter

shopt -s -o nounset

est quelque chose que vous pouvez ajouter au haut d'un script, qui fera une erreur si les variables ne sont pas déclaré n'importe où dans le script. Le message que vous voyez est unbound variable , mais comme d'autres le mentionnent, il n'attrapera pas de chaîne vide ou de valeur nulle. Pour s'assurer que n'importe quelle valeur individuelle n'est pas vide, nous pouvons tester une variable comme il est étendu avec ${mystr:?} , également connu sous le signe de dollar expansion, qui serait une erreur avec parameter null or not set .

1
répondu Sacrilicious 2012-07-21 16:19:56

Le Bash Manuel de Référence est une source d'information 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 section 6.3.2 .)

notez que l'espace blanc après l'ouverture [ et avant le ] est pas optionnel .


Conseils pour les utilisateurs de Vim

j'ai eu un script qui avait plusieurs déclarations comme suit:

export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part"

mais je voulais qu'ils s'en remettent à toutes les valeurs existantes. Alors je les ai réécrits pour qu'ils ressemblent à ceci:

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

j'ai pu automatiser cela dans vim en utilisant un regex rapide:

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

Ceci peut être appliqué en sélectionnant les lignes visuellement, puis en tapant : . La barre de commande pré-popule avec :'<,'> . Coller la commande ci-dessus et appuyer sur Entrée.


testé sur cette version de Vim:

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

les utilisateurs de Windows peuvent vouloir des fins de ligne différentes.

1
répondu funroll 2015-12-01 19:56:24

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

var_defined() {
    local var_name=
    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
0
répondu Swiss 2011-10-01 01:10:15

l'appel sans aucun argument.. il affiche tous les vars définis..

le dernier sur la liste seront ceux définis dans votre script..

donc vous pourriez pipe sa production à quelque chose qui pourrait comprendre ce que les choses sont définies et ce qui n'est pas

-3
répondu Aditya Mukherji 2008-10-23 04:36:34