Comment déterminer si une variable bash est vide?

765

Quel est le meilleur moyen de déterminer si une variable de bash est vide ("")?

J'ai entendu dire qu'il est recommandé que je fasse if [ "x$variable" = "x" ]

Est-ce la bonne façon? (il doit y avoir quelque chose de plus simple)

Brent
la source
Voir: Test pour une chaîne de longueur non nulle dans Bash sur StackOverflow.
codeforester

Réponses:

1053

Cela retournera true si une variable est non définie ou définie sur la chaîne vide ("").

if [ -z "$VAR" ];
duffbeer703
la source
14
Est-ce que cela inclut si une variable IS SET a une valeur de ""?
Brent
11
Oui, c'est le cas ... "-z" teste une chaîne de longueur nulle.
David Z
91
if [ ! -z "$VAR" ];
Aaron Copley
263
l'inverse de -zis-n if [ -n "$VAR" ];
Felipe Alvarez
19
Les guillemets doubles garantissent que la variable ne soit pas divisée. Un simple $varsur une ligne de commande sera divisé par son espace en une liste de paramètres, alors qu’il "$var"ne restera toujours qu’un seul paramètre. Citer des variables est souvent une bonne pratique et vous évite de vous lancer dans des noms de fichiers contenant des espaces (entre autres). Exemple: après avoir a="x --help"essayé cat $a, cela vous donnera la page d’aide pour cat. Ensuite, essayez cat "$a"- ce sera (généralement) dire cat: x --help: No such file or directory. En bref, citez tôt et citez souvent et vous ne le regretterez presque jamais.
Score_Under
247

Dans Bash, lorsque vous n'êtes pas concerné par la portabilité des shells qui ne le prennent pas en charge, vous devez toujours utiliser la syntaxe à double crochet:

N'importe lequel des éléments suivants:

if [[ -z $variable ]]
if [[ -z "$variable" ]]
if [[ ! $variable ]]
if [[ ! "$variable" ]]

Dans Bash, à l'aide de doubles crochets, les guillemets ne sont pas nécessaires. Vous pouvez simplifier le test pour une variable qui contient une valeur comme suit :

if [[ $variable ]]

Cette syntaxe est compatible avec ksh (au moins ksh93, de toute façon). Il ne fonctionne pas avec les coquilles POSIX ou Bourne plus anciennes telles que sh ou dash.

Voir ma réponse ici et BashFAQ / 031 pour plus d'informations sur les différences entre crochets simples et doubles.

Vous pouvez tester si une variable est spécifiquement non définie (par opposition à une chaîne vide):

if [[ -z ${variable+x} ]]

où le "x" est arbitraire.

Si vous voulez savoir si une variable est null mais pas non définie:

if [[ -z $variable && ${variable+x} ]]
Dennis Williamson
la source
1
Cela if [[ $variable ]]a bien fonctionné pour moi et je n’avais même pas besoin de ce set -uqui était requis par l’une des solutions proposées.
Teemu Leisti
3
Je pense que c'est mieux que la réponse acceptée.
Qed
2
Pourquoi recommandez-vous une fonctionnalité non portable alors que cela ne présente aucun avantage?
Alastair Irvine
19
@AlastairIrvine: Je mentionne la portabilité dans la première phrase de ma réponse, le titre de la question et le corps contiennent le mot « Bash » et la question est marqué bash , et la double structure de support offre des avantages évidents à bien des égards. Et je ne recommande pas de mélanger les styles de support pour des raisons de cohérence et de facilité de maintenance. Si vous avez besoin de la portabilité maximale, du plus petit commun dénominateur, utilisez shplutôt Bash. Si vous avez besoin des capacités accrues qu’il offre, utilisez Bash et utilisez-le pleinement.
Dennis Williamson
2
@BrunoBronosky: J'ai annulé l'édition. Il n'y a aucune exigence pour ;à la fin. Le thenpeut être sur la ligne suivante sans un point-virgule.
Dennis Williamson
230

Une variable dans bash (et n'importe quel shell compatible POSIX) peut être dans l'un des trois états suivants:

  • non fixé
  • mis à la chaîne vide
  • défini sur une chaîne non vide

La plupart du temps, il suffit de savoir si une variable est définie sur une chaîne non vide, mais il est parfois important de faire la distinction entre non défini et défini sur la chaîne vide.

Voici des exemples de la façon dont vous pouvez tester les différentes possibilités, et cela fonctionne dans bash ou n’importe quel shell compatible POSIX:

if [ -z "${VAR}" ]; then
    echo "VAR is unset or set to the empty string"
fi
if [ -z "${VAR+set}" ]; then
    echo "VAR is unset"
fi
if [ -z "${VAR-unset}" ]; then
    echo "VAR is set to the empty string"
fi
if [ -n "${VAR}" ]; then
    echo "VAR is set to a non-empty string"
fi
if [ -n "${VAR+set}" ]; then
    echo "VAR is set, possibly to the empty string"
fi
if [ -n "${VAR-unset}" ]; then
    echo "VAR is either unset or set to a non-empty string"
fi

Voici la même chose mais sous forme de tableau pratique:

                        +-------+-------+-----------+
                VAR is: | unset | empty | non-empty |
+-----------------------+-------+-------+-----------+
| [ -z "${VAR}" ]       | true  | true  | false     |
| [ -z "${VAR+set}" ]   | true  | false | false     |
| [ -z "${VAR-unset}" ] | false | true  | false     |
| [ -n "${VAR}" ]       | false | false | true      |
| [ -n "${VAR+set}" ]   | false | true  | true      |
| [ -n "${VAR-unset}" ] | true  | false | true      |
+-----------------------+-------+-------+-----------+

La ${VAR+foo}construction se développe en chaîne vide si VARest non défini ou to foosi VARest défini sur n'importe quoi (y compris la chaîne vide).

La ${VAR-foo}construction se développe à la valeur de VARif set (y compris set à la chaîne vide) et fooif non définie. Ceci est utile pour fournir des valeurs par défaut remplaçables par l'utilisateur (par exemple, ${COLOR-red}dit d'utiliser redsi la variable COLORn'a pas été définie sur quelque chose).

La raison pour laquelle il [ x"${VAR}" = x ]est souvent recommandé de vérifier si une variable est non définie ou définie sur une chaîne vide est due au fait que certaines implémentations de la [commande (également connues sous le nom de test) sont erronées. Si VARest défini sur quelque chose comme -n, dans ce cas , certaines implémentations ne fonctionneront pas correctement [ "${VAR}" = "" ]car le premier argument de [est interprété à tort comme un -nopérateur, et non comme une chaîne.

Richard Hansen
la source
3
Le test d'une variable définie sur la chaîne vide peut également être effectué à l'aide de [ -z "${VAR-set}" ].
Nwellnhof
@nwellnhof: Merci! J'ai mis à jour ma réponse pour utiliser la syntaxe plus courte.
Richard Hansen
Quelle est la différence entre la première et la dernière construction? Ils correspondent tous les deux à "VAR est soit non défini, soit défini sur une chaîne non vide".
Faheem Mitha
1
@FaheemMitha: Ce n'est pas votre faute - ma réponse était difficile à lire. J'ai ajouté un tableau pour rendre la réponse plus claire, espérons-le.
Richard Hansen
2
Les contrôles non définis ne sont pas fiables. Si l'utilisateur a appelé set -uou set -o nounseten bash, le test entraînera simplement l'erreur "bash: VAR: variable non liée". Voir stackoverflow.com/a/13864829 pour une vérification non définie plus fiable. Mon go-to vérifier si une variable est null ou non définie est [ -z "${VAR:-}" ]. Mon chèque pour savoir si une variable est non vide est [ "${VAR:-}" ].
Kevin Jin
38

-z est le meilleur moyen.

Une autre option que j'ai utilisée est de définir une variable, mais elle peut être remplacée par une autre variable, par exemple

export PORT=${MY_PORT:-5432}

Si la $MY_PORTvariable est vide, la valeur PORTest définie sur 5432, sinon PORT est défini sur la valeur MY_PORT. Notez que la syntaxe inclut les deux points et le tiret.

Rory
la source
J'ai trouvé cela accidentellement aujourd'hui, et c'était exactement ce que je voulais. Merci! Je dois tolérer set -o nounsetdans certains scripts.
Opello
24

Si vous souhaitez distinguer les cas d'état jeu vide ou non défini, regardez l'option -u pour bash:

$ set -u
$ echo $BAR
bash: BAR: unbound variable
$ [ -z "$BAR" ] && echo true
bash: BAR: unbound variable
$ BAR=""
$ echo $BAR

$ [ -z "$BAR" ] && echo true
true
MikeyB
la source
8

Voici une alternative que j'ai vue [ -z "$foo" ], mais je ne suis pas sûr de savoir pourquoi les gens utilisent cette méthode, tout le monde le sait?

[ "x${foo}" = "x" ]

Quoi qu'il en soit, si vous n'autorisez pas les variables non définies (par set -uou set -o nounset), vous rencontrerez des problèmes avec ces deux méthodes. Il y a une solution simple à ceci:

[ -z "${foo:-}" ]

Note: cela laissera votre variable undef.

errant.info
la source
3
Il y a un commentaire à propos de l'alternative -zà pubs.opengroup.org/onlinepubs/009695399/utilities/test.html . Fondamentalement, ce n'est pas censé être une alternative à -z. Plutôt, il gère les cas où $foopourrait s'étendre à quelque chose commençant par un métacaractère qui serait [ou testserait confus par. Mettre un non-métacaractère arbitraire au début élimine cette possibilité.
James Sneeringer
6

La question demande comment vérifier si une variable est une chaîne vide et les meilleures réponses sont déjà données pour cela.
Mais j'ai atterri ici après une période passée en programmation en php et ce que je cherchais était en fait un test similaire à la fonction vide en php fonctionnant dans un shell bash.
Après avoir lu les réponses, je me suis rendu compte que je ne pensais pas correctement dans bash, mais de toute façon, à ce moment-là, une fonction comme vide dans php aurait été très utile dans mon code bash.
Comme je pense que cela peut arriver à d’autres, j’ai décidé de convertir la fonction php empty en bash

selon le manuel php :
une variable est considérée comme vide si elle n'existe pas ou si sa valeur est l'une des suivantes:

  • "" (une chaîne vide)
  • 0 (0 sous forme d'entier)
  • 0.0 (0 en float)
  • "0" (0 sous forme de chaîne)
  • un tableau vide
  • une variable déclarée, mais sans valeur

Bien sûr, les cas nul et faux ne peuvent pas être convertis en bash, ils sont donc omis.

function empty
{
    local var="$1"

    # Return true if:
    # 1.    var is a null string ("" as empty string)
    # 2.    a non set variable is passed
    # 3.    a declared variable or array but without a value is passed
    # 4.    an empty array is passed
    if test -z "$var"
    then
        [[ $( echo "1" ) ]]
        return

    # Return true if var is zero (0 as an integer or "0" as a string)
    elif [ "$var" == 0 2> /dev/null ]
    then
        [[ $( echo "1" ) ]]
        return

    # Return true if var is 0.0 (0 as a float)
    elif [ "$var" == 0.0 2> /dev/null ]
    then
        [[ $( echo "1" ) ]]
        return
    fi

    [[ $( echo "" ) ]]
}



Exemple d'utilisation:

if empty "${var}"
    then
        echo "empty"
    else
        echo "not empty"
fi



Démo:
l'extrait suivant:

#!/bin/bash

vars=(
    ""
    0
    0.0
    "0"
    1
    "string"
    " "
)

for (( i=0; i<${#vars[@]}; i++ ))
do
    var="${vars[$i]}"

    if empty "${var}"
        then
            what="empty"
        else
            what="not empty"
    fi
    echo "VAR \"$var\" is $what"
done

exit

les sorties:

VAR "" is empty
VAR "0" is empty
VAR "0.0" is empty
VAR "0" is empty
VAR "1" is not empty
VAR "string" is not empty
VAR " " is not empty

Cela dit, dans une logique bash, les vérifications de zéro dans cette fonction peuvent entraîner des problèmes secondaires, toute personne utilisant cette fonction devrait évaluer ce risque et peut-être décider de supprimer ces vérifications en ne laissant que le premier.

Luca Borrione
la source
Dans la fonction empty- pourquoi avez-vous écrit [[ $( echo "1" ) ]] ; returnau lieu de simplement return 1?
Dor
5

l'ensemble if-then et -z est inutile.

["$ foo"] && echo "foo n'est pas vide"
["$ foo"] || echo "foo est en effet vide"

la source
3
Cela échouera si foo ne contient que des espaces
Brian
2
Échouera également dans certains coquillages si foo commence par un tiret puisqu'il est interprété comme une option. Par exemple, sur Solaris, ksh , zsh et bash ne posent aucun problème, sh et / bin / test échoueront
ktf
4

Ceci est vrai exactement quand $ FOO est défini et vide:

[ "${FOO+x}" = x ] && [ -z "$FOO" ]

la source
4

Personnellement, préférez un moyen plus clair de vérifier:

if [ "${VARIABLE}" == "" ]; then
  echo VARIABLE is empty
else
  echo VARIABLE is not empty
fi
Fedir RYKHTIK
la source
1
Certains coquillages n'acceptent pas le double signe égal.
Dennis Williamson
1
La question portait sur bash. J'utilise bash. Fonctionne bien pour moi. De quoi parlez-vous exactement?
Fedir RYKHTIK
2
Si vous utilisez Bash, vous devez utiliser des crochets doubles. Mon commentaire précédent était une simple déclaration de fait pour ceux qui pourraient lire votre réponse et utiliser un shell différent.
Dennis Williamson
les crochets simples sont corrects dans ce cas, veuillez consulter serverfault.com/questions/52034/…
Luca Borrione
4

extension de la solution duffbeer703 :

#! /bin/bash
[ -z "$1" ] || some_command_that_needs_$1_parameter
Andrej
la source
4

Mes 5 centimes: il existe aussi une syntaxe plus courte que if ...celle-ci:

VALUE="${1?"Usage: $0 value"}"

Cette ligne définira VALEUR si un argument a été fourni et imprimera un message d'erreur précédé du numéro de ligne du script en cas d'erreur (et mettra fin à l'exécution du script).

Vous trouverez un autre exemple dans le guide des abs (recherchez "Exemple 10-7").

gluk47
la source
0

Pas une réponse exacte, mais a rencontré cette astuce. Si la chaîne que vous recherchez provient d'une "commande", vous pouvez alors la stocker dans un env. variable et ensuite l'exécuter à chaque fois pour l'instruction if, aucun crochet n'est requis!

Par exemple, cette commande, qui détermine si vous êtes sur debian:

grep debian /proc/version

exemple complet:

IS_DEBIAN="grep -i debian /proc/version"

if $IS_DEBIAN; then
  echo 'yes debian'
else
  echo 'non debian'
fi

Il s’agit donc d’une manière indirecte (en l’exécutant à chaque fois) de rechercher une chaîne vide (il s’agit de rechercher une réponse d’erreur de la commande, mais il renvoie également une chaîne vide).

rogerdpack
la source