web-dev-qa-db-fra.com

Comment puis-je tester si une variable est vide ou ne contient que des espaces?

La syntaxe bash suivante vérifie si param n'est pas vide:

 [[ !  -z  $param  ]]

Par exemple:

param=""
[[ !  -z  $param  ]] && echo "I am not zero"

Pas de sortie et c'est bien.

Mais lorsque param est vide sauf pour un (ou plusieurs) espace, le cas est différent:

param=" " # one space
[[ !  -z  $param  ]] && echo "I am not zero"

"Je ne suis pas nul" est affiché.

Comment puis-je modifier le test pour considérer les variables qui ne contiennent que des caractères d'espace comme vides?

261
maihabunash

Tout d'abord, notez que le test -z est explicitement pour:

la longueur de la chaîne est nulle

Autrement dit, une chaîne contenant uniquement des espaces ne doit pas être vraie sous -z, Car elle a une longueur non nulle.

Ce que vous voulez, c'est supprimer les espaces de la variable en utilisant expansion du paramètre de remplacement de modèle :

[[ -z "${param// }" ]]

Cela étend la variable param et remplace toutes les correspondances du modèle (un seul espace) par rien, donc une chaîne qui ne contient que des espaces sera développée en une chaîne vide.


le détail de la façon dont cela fonctionne est que ${var/pattern/string} Remplace la première correspondance la plus longue de pattern par string. Lorsque pattern commence par / (Comme ci-dessus), il remplace tous les correspondances. Parce que le remplacement est vide, nous pouvons omettre la valeur finale / Et la valeur string:

$ {paramètre/motif/chaîne}

Le motif est développé pour produire un motif comme dans l'expansion du nom de fichier. Paramètre est développé et la plus longue correspondance de motif par rapport à sa valeur est remplacée par chaîne. Si motif commence par ‘/’, toutes les correspondances de motif sont remplacées par chaîne. Normalement, seul le premier match est remplacé. ... Si string est null, les correspondances de pattern sont supprimées et le /= pattern peut être omis.

Après tout cela, nous nous retrouvons avec ${param// } Pour supprimer tous les espaces.

Notez que bien que présente dans ksh (d'où elle provient), zsh et bash, cette syntaxe n'est pas POSIX et ne doit pas être utilisée dans les scripts sh.

304
Michael Homer

Le moyen simple de vérifier qu'une chaîne ne contient que des caractères dans un ensemble autorisé consiste à tester la présence de caractères non autorisés. Ainsi, au lieu de tester si la chaîne ne contient que des espaces, testez si la chaîne contient un caractère autre que l'espace. En bash, ksh ou zsh:

if [[ $param = *[!\ ]* ]]; then
  echo "\$param contains characters other than space"
else
  echo "\$param consists of spaces only"
fi

"Se compose uniquement d'espaces" inclut le cas d'une variable vide (ou non définie).

Vous voudrez peut-être tester tout caractère d'espacement. Utilisez [[ $param = *[^[:space:]]* ]] Pour utiliser les paramètres régionaux ou la liste explicite de caractères d'espacement que vous souhaitez tester, par exemple [[ $param = *[$' \t\n']* ]] Pour tester l'espace, la tabulation ou la nouvelle ligne.

Faire correspondre une chaîne à un modèle avec = À l'intérieur de [[ … ]] Est une extension ksh (également présente dans bash et zsh). Dans n'importe quel style Bourne/POSIX, vous pouvez utiliser la construction case pour faire correspondre une chaîne à un modèle. Notez que les modèles Shell standard utilisent ! Pour annuler un jeu de caractères, plutôt que ^ Comme dans la plupart des syntaxes d'expressions régulières.

case "$param" in
  *[!\ ]*) echo "\$param contains characters other than space";;
  *) echo "\$param consists of spaces only";;
esac

Pour tester les espaces, la syntaxe $'…' Est spécifique à ksh/bash/zsh; vous pouvez insérer ces caractères dans votre script littéralement (notez qu'une nouvelle ligne devra être entre guillemets, car la barre oblique inverse + la nouvelle ligne se développe à rien), ou les générer, par exemple.

whitespace=$(printf '\n\t ')
case "$param" in
  *[!$whitespace]*) echo "\$param contains non-whitespace characters";;
  *) echo "\$param consists of whitespace only";;
esac

POSIX:

case $var in
  (*[![:blank:]]*) echo '$var contains non blank';;
  (*) echo '$var contains only blanks or is empty or unset'
esac

Pour faire la distinction entre vide, non vide, vide, non défini:

case ${var+x$var} in
  (x) echo empty;;
  ("") echo unset;;
  (x*[![:blank:]]*) echo non-blank;;
  (*) echo blank
esac

[:blank:] est pour les caractères d'espacement horizontal (espace et tabulation en ASCII, mais il y en a probablement un peu plus dans vos paramètres régionaux; certains systèmes incluront l'espace insécable (le cas échéant), d'autres non). Si vous souhaitez également des caractères d'espacement vertical (comme le saut de ligne ou le saut de page), remplacez [:blank:] avec [:space:].

22
Stéphane Chazelas

La seule raison restante d'écrire un script Shell, au lieu d'un script dans un langage de script bon, est si l'extrême portabilité est une préoccupation primordiale. L'héritage /bin/sh est la seule chose dont vous pouvez être certain, mais Perl, par exemple, est plus susceptible d'être multiplateforme que Bash. Par conséquent, n'écrivez jamais de scripts Shell qui utilisent des fonctionnalités qui ne sont pas vraiment universelles - et gardez à l'esprit que plusieurs fournisseurs Unix propriétaires ont gelé leur environnement Shell avant POSIX.1-2001 .

Il existe un moyen portable de faire ce test, mais vous devez utiliser tr:

[ "x`printf '%s' "$var" | tr -d "$IFS"`" = x ]

(La valeur par défaut de $IFS, commodément, est un espace, un onglet et une nouvelle ligne.)

(Le programme intégré printf est lui-même très portable, mais il est beaucoup moins compliqué de s'y fier que de déterminer la variante de echo dont vous disposez.)

5
zwol
if [[ -n "${variable_name/[ ]*\n/}" ]]
then
    #execute if the the variable is not empty and contains non space characters
else
    #execute if the variable is empty or contains only spaces
fi
5
Guru

Le code que vous avez publié [[ ! -z $param ]] && echo "I am not zero" imprimera I am not zero si param est non défini/non défini ou vide (en bash, ksh et zsh).

Pour aussi imprimer si param ne contient que des espaces (supprimer les espaces), POSIXly (pour une plus large gamme de shells):

 [   -z "${param#"${param%%[! ]*}"}"   ] && echo "empty"

Explication:

  • UNE ${param# … } supprime un texte en tête.
  • Ce texte de tête est donné par: ${param%%[! ]*}
  • Qui se développe en tous les espaces avant tout non-espace caractère, c'est-à-dire tous les espaces de début.

Le résultat final de toute l'expansion est que tous les espaces de tête sont supprimés.

Ce résultat étendu est testé s'il est de longueur 0.

  • Si le résultat est vide, alors soit la variable était vide, soit
  • supprimer les espaces de tête le rendait vide.

Par conséquent, si le test est vrai, la variable était déjà vide ou n'avait que des espaces à l'intérieur.


Le concept est facile à étendre à plus de types de caractères. Pour inclure également des onglets, placez un onglet explicite à l'intérieur de l'expression de parenthèse:

 [ -z "${param#"${param%%[!     ]*}"}" ] && echo "empty"

ou utilisez une variable avec les caractères dont vous avez besoin supprimés:

 var=$' \t'                                    # in ksh, bash, zsh
 [ -z "${param#"${param%%[!$var]*}"}" ] && echo "empty"

ou vous pouvez utiliser une "expression de classe de caractères" POSIX (vide signifie espace et tabulation):

 [ -z "${param#"${param%%[![:blank:]]*}"}" ] && echo "empty"
1
Isaac

Pour tester si la variable est vide ou contient des espaces, vous pouvez également utiliser ce code:

${name:?variable is empty}
1
pratik