28 votes

Tester si une variable Bash est désactivée, en utilisant une fonction.

Un test simple de la variable Bash :

${varName:?    "${varName} is not defined"}

J'aimerais réutiliser ceci, en le mettant dans une fonction. Comment puis-je le faire ?

Les échecs suivants

#
# Test a variable exists
tvar(){
 val=${1:?    "${1}    must be defined, preferably in $basedir"}
 if [ -z ${val}  ]
     then
     echo Zero length value
 else
     echo ${1} exists, value ${1}
 fi
}

C'est-à-dire que je dois sortir si le test échoue.

0 votes

Votre titre dit "unset", mais votre exemple teste "unset ou set à la chaîne vide". Quel est le cas qui vous intéresse ?

46voto

Dennis Williamson Points 105818

Merci à de lhunath réponse, j'ai été conduit à une partie du Bash man page que j'ai négligée des centaines de fois :

    When  not performing substring  expansion, bash tests for a parameter that
    is unset  or null; omitting the colon results in a test only for a parame‐
    ter that is unset.

Cela m'a incité à créer la table de vérité suivante :

                | unset |   set    | set and  | meaning
                |       | but null | not null |
    ============+=======+==========+==========+=============================
     ${var-\_}   |   T   |     F    |    T     | not null or not set
    ------------+-------+----------+----------+-----------------------------
     ${var:-\_}  |   T   |     T    |    T     | always true, use for subst.
    ------------+-------+----------+----------+-----------------------------
     $var       |   F   |     F    |    T     | var is set and not null
    ------------+-------+----------+----------+-----------------------------
     ${!var\[@\]} |   F   |     T    |    T     | var is set

Ce tableau introduit la spécification dans la dernière ligne. Le Bash man dit "Si le nom n'est pas un tableau, se développe à 0 si le nom est défini et à null sinon". Pour les besoins de cette table de vérité, il se comporte de la même manière même si c'est un tableau.

0 votes

Très cool, mais savez-vous pourquoi cela échoue lorsque var est un tableau : test "${!var[@]}" && echo 'T' || echo 'F' message d'erreur binary operator expected

0 votes

@l0b0 : Ca me donne un "T" ou un "F" selon que var est activé ou désactivé. Quel shell (et sa version) ? (Cela ne fonctionne qu'en Bash.) Quel est le contenu du fichier ${var[@]} (sortie de declare -p var ) ?

0 votes

Bash 4.1.5(1)-release (i486-pc-linux-gnu) , declare -a var='([0]="var1" [1]="var2" [2]="var3")' . Voir Gist

19voto

lhunath Points 27045

Ce que vous cherchez, c'est l'indirection.

assertNotEmpty() {
    : "${!1:? "$1 is empty, aborting."}"
}

Cela entraîne l'abandon du script avec un message d'erreur si vous faites quelque chose comme ceci :

$ foo=""
$ assertNotEmpty foo
bash: !1:  foo is empty, aborting.

Si vous voulez juste test si foo est vide, au lieu d'interrompre le script, utilisez ceci à la place d'une fonction :

[[ $foo ]]

Par exemple :

until read -p "What is your name? " name && [[ $name ]]; do
    echo "You didn't enter your name.  Please, try again." >&2
done

Notez également qu'il existe un différence très importante entre un vide et un non activé paramètre. Il faut faire attention à ne pas confondre ces termes ! Un paramètre vide est un paramètre qui est défini, mais juste défini par une chaîne vide. Un paramètre non défini est un paramètre qui n'existe pas du tout.

Les exemples précédents testent tous la présence de vide paramètres. Si vous voulez tester non activé et considérer tous les paramètres définis comme OK, qu'ils soient vides ou non, utilisez ceci :

[[ ! $foo && ${foo-_} ]]

Utilisez-le dans une fonction comme celle-ci :

assertIsSet() {
    [[ ! ${!1} && ${!1-_} ]] && {
        echo "$1 is not set, aborting." >&2
        exit 1
    }
}

Ce qui n'interrompt le script que lorsque le nom du paramètre que vous passez désigne un paramètre qui n'est pas défini :

$ ( foo="blah"; assertIsSet foo; echo "Still running." )
Still running.
$ ( foo=""; assertIsSet foo; echo "Still running." )
Still running.
$ ( unset foo; assertIsSet foo; echo "Still running." )
foo is not set, aborting.

0 votes

C'est celui-là que je veux. Merci. J'aurais dû dire unset. Donc la fonction que je veux est assertIsSet() { [[ ! ${!1} && ${!1-_} ]] && { echo "$1 is not set, aborting." >&2 exit 1 } } Merci.

0 votes

Pour les versions plus récentes de bash, le test [[ ! -v var ]] ne sera vrai que si la variable est désactivée. Cela semble plus facile que le double test dans assertIsSet . :)

6voto

dnozay Points 3672

Vous voulez utiliser [ -z ${parameter+word} ]

Une partie de man bash :

Parameter Expansion
    ...
    In each of the cases below, word is subject to
    tilde expansion, parameter expansion, command
    substitution, and arithmetic expansion.  When
    not performing substring expansion, bash
    tests for a parameter that is unset or
    null; omitting the colon results in a
    test only for a parameter that is unset.
    ...
    ${parameter:+word}
           Use Alternate Value.  If parameter is
           null or unset, nothing is substituted,
           otherwise the expansion of word is
           substituted.
    ...

En d'autres termes :

${parameter+word}
       Use Alternate Value.  If parameter is unset,
       nothing is substituted, otherwise the
       expansion of word is substituted.

Quelques exemples :

$ set | grep FOOBAR
$ if [ -z "${FOOBAR+something}" ]; then echo "it is unset"; fi
it is unset
$ declare FOOBAR
$ if [ -z "${FOOBAR+something}" ]; then echo "it is unset"; fi
$ FOOBAR=
$ if [ -z "${FOOBAR+something}" ]; then echo "it is unset"; fi
$ FOOBAR=1
$ if [ -z "${FOOBAR+something}" ]; then echo "it is unset"; fi
$ unset FOOBAR
$ if [ -z "${FOOBAR+something}" ]; then echo "it is unset"; fi
it is unset

1 votes

Que fait "set | grep FOOBAR" ?

3voto

Cette fonction recherche les variables qui sont actuellement set. La variable peut même être un tableau. Notez qu'en Bash : 0 == VRAI, 1 == FAUX.

function var.defined {
    eval '[[ ${!'$1'[@]} ]]'
}

# Typical usage of var.defined {}

declare you="Your Name Here" ref='you';

read -p "What's your name: " you;

if var.defined you; then   # Simple demo using literal text

    echo "BASH recognizes $you";
    echo "BASH also knows a reference to $ref as ${!ref}, by indirection.";

fi

unset you # Have just been killed by a master :D

if ! var.defined $ref; then    # Standard demo using an expanded literal value

    echo "BASH doesn't know $ref any longer";

fi

read -s -N 1 -p "Press any key to continue...";
echo "";

Pour être clair ici, la fonction teste le texte littéral. Chaque fois qu'une commande est appelée dans Bash, les variables sont généralement à moins que la valeur sous-jacente ne soit "échangée" ou "substituée" :

  • $varRef ($) est échappé : $varRef
  • $varRef est une citation simple '$varRef'.

1voto

Andrea Francia Points 2894

Je n'ai pas compris exactement ce dont vous avez besoin. J'essaie de vous répondre malgré tout.

C'est-à-dire que je dois sortir si le test échoue.

Le code :

${varName:?    "${varName} is not defined"}

retournera un code de sortie non nul s'il n'y a pas de variable nommée "varName". Le code de sortie de la dernière commande est enregistré dans le fichier $? .

A propos de votre code :

val=${1:?    "${1}    must be defined, preferably in $basedir"}

Peut-être qu'il ne fait pas ce dont vous avez besoin. Dans le cas où $1 n'est pas définie, la "${1}" sera substitué par rien. Vous voulez probablement utiliser les guillemets simples qui écrivent littéralement ${1} sans substitution.

val=${1:?    '${1}    must be defined, preferably in $basedir'

0 votes

Je veux encapsuler le test dans une fonction, pour me permettre de l'appeler avec la définition de SomeVariableName afin de pouvoir le réutiliser.

0 votes

Ma fonction terminée, teste à la fois pour unset et empty (ceinture et accolades) assertIsSet2() { if [[ ! ${!1} && ${!1-_} ]]] then echo "$1 is not set, aborting." >&2 exit 1 #else # echo ${1} is set, value [${1}] fi : "${!1: ? "$1 est vide, abandon de l'opération."}" } Merci pour votre contribution. Je suis de nouveau sur la bonne voie !

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