Dans Bash, comment tester si une variable est définie en mode "- u"

je viens de découvrir set -u à bash et cela m'a aidé à trouver plusieurs bogues jusqu'ici inconnus. Mais j'ai aussi un scénario où je dois tester si une variable est définie avant de calculer une valeur par défaut. Le mieux que j'ai trouvé pour cela est:

if [ "${variable-undefined}" == undefined ]; then
    variable="$(...)"
fi

qui fonctionne (tant que la variable n'a pas la valeur de chaîne undefined ). Je me demandais si il y avait une meilleure façon?

46
demandé sur Ramon 2012-07-06 16:31:05

7 réponses

Ce qui Ne fonctionne pas: Test de Chaînes de Longueur Nulle

vous pouvez tester des chaînes non définies de plusieurs façons. En utilisant la condition de test standard ressemble à ceci:

# Test for zero-length string.
[ -z "$variable" ] || variable='foo'

Cela ne fonctionnera pas avec set -u , cependant.

Ce Qui Fonctionne: Cession Conditionnelle

alternativement, vous pouvez utiliser l'assignation conditionnelle, qui est une façon plus Bash-like pour le faire. Par exemple:

# Assign value if variable is unset or null.
: "${variable:=foo}"

en raison de la façon dont Bash gère l'expansion de cette expression, vous pouvez l'utiliser en toute sécurité avec set -u sans obtenir une erreur" bash: variable: unbound variable".

29
répondu Todd A. Jacobs 2012-07-06 12:44:09

C'est ce que j'ai trouvé qui fonctionne le mieux pour moi, en s'inspirant des autres réponses:

if [ -z "${varname-}" ]; then
  ...
  varname=$(...)
fi
50
répondu Ramon 2012-07-06 20:40:11

dans bash 4.2 et les versions plus récentes, il existe une façon explicite de vérifier si une variable est définie, qui est d'utiliser-v. L'exemple de la question pourrait alors être mis en œuvre comme ceci:

if [[ ! -v variable ]]; then
   variable="$(...)"
fi

voir http://www.gnu.org/software/bash/manual/bashref.html#Bash-Conditional-Expressions

si vous voulez seulement définir la variable, si elle n'est pas déjà définie, vous êtes probablement mieux de faire quelque chose dans ce sens:

variable="${variable-$(...)}"

notez qu'il ne s'agit pas d'une variable définie mais vide.

7
répondu Felix Leipold 2015-04-02 02:02:14

les réponses ci-dessus ne sont pas dynamiques, par exemple, comment tester est variable avec le nom "mannequin" est défini? Essayez ceci:

is_var_defined()
{
    if [ $# -ne 1 ]
    then
        echo "Expected exactly one argument: variable name as string, e.g., 'my_var'"
        exit 1
    fi
    # Tricky.  Since Bash option 'set -u' may be enabled, we cannot directly test if a variable
    # is defined with this construct: [ ! -z "$var" ].  Instead, we must use default value
    # substitution with this construct: [ ! -z "${var:-}" ].  Normally, a default value follows the
    # operator ':-', but here we leave it blank for empty (null) string.  Finally, we need to
    # substitute the text from  as 'var'.  This is not allowed directly in Bash with this
    # construct: [ ! -z "${:-}" ].  We need to use indirection with eval operator.
    # Example: ="var"
    # Expansion for eval operator: "[ ! -z ${:-} ]" -> "[ ! -z ${var:-} ]"
    # Code  execute: [ ! -z ${var:-} ]
    eval "[ ! -z ${:-} ]"
    return $?  # Pedantic.
}

Related: Comment vérifier si une variable est définie dans Bash?

4
répondu kevinarpe 2017-05-23 12:10:32

au début de votre script, vous pouvez définir vos variables avec une valeur vide

variable_undefined=""

puis

if [ "${variable_undefined}" == "" ]; then
    variable="$(...)"
fi
1
répondu Luc M 2012-07-06 12:34:33

malheureusement [[ -v variable ]] n'est pas pris en charge dans les anciennes versions de bash (du moins pas dans la version 4.1.5 que J'ai sur Debian Squeeze)

vous pouvez utiliser un sous-shell comme ceci:

if (true $variable)&>/dev/null; then
    variable="$(...)"
fi
1
répondu efa 2014-04-11 10:35:02
if [ "${var+SET}" = "SET" ] ; then
    echo "$var = ${var}"
fi

Je ne sais pas jusqu'où ${var+value} est supporté, mais cela fonctionne au moins aussi loin que 4.1.2. Les anciennes versions n'avaient pas $ {var+value}, elles n'avaient que ${var:+value}. La différence est que ${var:+valeur} seulement évaluer la "valeur" si $var est réglé à une non vide de la chaîne, tandis que ${var+valeur} permettra également d'évaluer la "valeur" si $var est vide.

sans [[- V var ]] ou ${var+value} je pense que vous devriez utiliser une autre méthode. Probablement un test de subshell comme il a été décrit dans une réponse précédente:

if ( set -u; echo "$var" ) &> /dev/null; then
    echo "$var = ${var}
fi

si votre processus shell a déjà" set-u "actif, il sera aussi actif dans le sous-puits sans avoir besoin de" set-u "à nouveau, mais l'inclure dans la commande sous-puits permet à la solution de fonctionner aussi si le processus parent n'a pas activé" set-u".

(Vous pouvez aussi utiliser un autre processus comme "printenv" ou "env" pour tester la présence de la variable, mais cela ne fonctionnerait que si la variable est exportée.)

0
répondu George 2016-03-04 00:49:55