Comment tester si une variable est définie dans Bash avant la version 4.2 avec l'option shell du nomset?

Pour les versions Bash antérieures à "GNU bash, Version 4.2", existe-t-il des alternatives équivalentes pour l'option -v de la command test ? Par exemple:

 shopt -os nounset test -v foobar && echo foo || echo bar # Output: bar foobar= test -v foobar && echo foo || echo bar # Output: foo 

Portable à tous les obus POSIX:

 if [ -n "${foobar+1}" ]; then echo "foobar is defined" else echo "foobar is not defined" fi 

Faites que ${foobar:+1} si vous voulez traiter foobar la même manière, qu'elle soit vide ou non définie. Vous pouvez également utiliser ${foobar-} pour get une string vide lorsque foobar est indéfini et la valeur de foobar cas contraire (ou mettre une autre valeur par défaut après le - ).

Dans ksh, si foobar est déclaré mais non défini, comme dans typeset -a foobar , alors ${foobar+1} s'étend à la string vide.

Zsh n'a pas de variables déclarées mais pas définies: typeset -a foobar crée un tableau vide.

En bash, les arrays se comportent de manière différente et surprenante. ${a+1} ne prend que 1 si a est un tableau non vide, par exemple

 typeset -aa; echo ${a+1} # prints nothing e=(); echo ${e+1} # prints nothing! f=(''); echo ${f+1} # prints 1 

Le même principe s'applique aux arrays associatifs: les variables masortingcielles sont traitées comme définies si elles ont un set d'index non vide.

Un moyen différent, bash-spécifique de tester si une variable de n'importe quel type a été définie est de vérifier s'il est répertorié dans ${! PREFIX *} ${! PREFIX *} . Cela rapporte les arrays vides tels que définis, contrairement à ${foobar+1} , mais rapporte les variables déclarées mais non assignées ( unset foobar; typeset -a foobar ) comme indéfini.

 case " ${!foobar*} " in *" foobar "*) echo "foobar is defined";; *) echo "foobar is not defined";; esac 

Cela équivaut à tester la valeur de return de typeset -p foobar ou à declare -p foobar , sauf que le typeset -p foobar échoue sur les variables déclarées mais non assignées.

Dans bash, comme dans ksh, set -o nounset; typeset -a foobar; echo $foobar set -o nounset; typeset -a foobar; echo $foobar set -o nounset; typeset -a foobar; echo $foobar triggers une erreur dans la tentative d'extension de la variable indéfinie foobar . Contrairement à ksh, set -o nounset; foobar=(); echo $foobar set -o nounset; foobar=(); echo $foobar set -o nounset; foobar=(); echo $foobar (ou echo "${foobar[@]}" ) triggers également une erreur.

Notez que dans toutes les situations décrites ici, ${foobar+1} s'étend à la string vide si et seulement si $foobar provoquerait une erreur sous set -o nounset .

Pour résumer avec la réponse de Gilles, j'ai inventé les règles suivantes:

  1. Utilisez [[ -v foobar ]] pour les variables dans la version Bash> = 4.2.
  2. Utilisez declare -p foobar &>/dev/null pour les variables de tableau dans la version Bash <4.2.
  3. Utilisez (( ${foo[0]+1} )) ou (( ${bar[foo]+1} )) pour les indices des arrays indexés ( -a ) et keyed ( -A ). Les options 1 et 2 ne fonctionnent pas ici.

J'utilise la même technique pour toutes les variables dans bash, et cela fonctionne, par exemple:

 [ ${foobar} ] && echo "foobar is set" || echo "foobar is unset" 

les sorties:

 foobar is unset 

tandis que

 foobar=( "val" "val2" ) [ ${foobar} ] && echo "foobar is set" || echo "foobar is unset" 

les sorties:

 foobar is set