web-dev-qa-db-fra.com

Test de la longueur non nulle de la chaîne dans Bash: [-n "$ var"] ou ["$ var"]

J'ai vu des scripts bash tester la chaîne de longueur non nulle de deux manières différentes. La plupart des scripts utilisent l'option -n:

#!/bin/bash
# With the -n option
if [ -n "$var" ]; then
  # Do something when var is non-zero length
fi

Mais l'option -n n'est pas vraiment nécessaire:

# Without the -n option
if [ "$var" ]; then
  # Do something when var is non-zero length
fi

Quel est le meilleur moyen?

De même, quel est le meilleur moyen de tester la longueur nulle:

if [ -z "$var" ]; then
  # Do something when var is zero-length
fi

ou

if [ ! "$var" ]; then
  # Do something when var is zero-length
fi
156
AllenHalsey

Edit: Ceci est une version plus complète qui montre plus de différences entre [ (aka test) et [[.

Le tableau suivant montre que le fait qu’une variable soit entre guillemets ou non, que vous utilisiez un seul ou deux crochets et que la variable ne contienne qu’un espace, a une incidence sur l’utilisation d’un test avec ou sans -n/-z convient pour vérifier une variable.

     | 1a    2a    3a    4a    5a    6a   | 1b    2b    3b    4b    5b    6b
     | [     ["    [-n   [-n"  [-z   [-z" | [[    [["   [[-n  [[-n" [[-z  [[-z"
-----+------------------------------------+------------------------------------
unset| false false true  false true  true | false false false false true  true
null | false false true  false true  true | false false false false true  true
space| false true  true  true  true  false| true  true  true  true  false false
zero | true  true  true  true  false false| true  true  true  true  false false
digit| true  true  true  true  false false| true  true  true  true  false false
char | true  true  true  true  false false| true  true  true  true  false false
hyphn| true  true  true  true  false false| true  true  true  true  false false
two  | -err- true  -err- true  -err- false| true  true  true  true  false false
part | -err- true  -err- true  -err- false| true  true  true  true  false false
Tstr | true  true  -err- true  -err- false| true  true  true  true  false false
Fsym | false true  -err- true  -err- false| true  true  true  true  false false
T=   | true  true  -err- true  -err- false| true  true  true  true  false false
F=   | false true  -err- true  -err- false| true  true  true  true  false false
T!=  | true  true  -err- true  -err- false| true  true  true  true  false false
F!=  | false true  -err- true  -err- false| true  true  true  true  false false
Teq  | true  true  -err- true  -err- false| true  true  true  true  false false
Feq  | false true  -err- true  -err- false| true  true  true  true  false false
Tne  | true  true  -err- true  -err- false| true  true  true  true  false false
Fne  | false true  -err- true  -err- false| true  true  true  true  false false

Si vous voulez savoir si une variable a une longueur non nulle, effectuez l'une des opérations suivantes:

  • citez la variable entre parenthèses (colonne 2a)
  • utilisation -n et citez la variable entre parenthèses (colonne 4a)
  • utilisez des crochets doubles avec ou sans guillemets et avec ou sans -n (colonnes 1b à 4b)

Dans la colonne 1a, notez à partir de la ligne "deux" que le résultat indique que [ évalue le contenu de la variable comme s’ils faisaient partie de l’expression conditionnelle (le résultat correspond à l’assertion implicite du "T" ou du " F "dans la colonne de description). Quand [[ est utilisé (colonne 1b), le contenu de la variable est vu comme une chaîne et n'est pas évalué.

Les erreurs dans les colonnes 3a et 5a sont causées par le fait que la valeur de la variable inclut un espace et que la variable est non citée. De nouveau, comme indiqué dans les colonnes 3b et 5b, [[ évalue le contenu de la variable en tant que chaîne.

De manière correspondante, pour les tests de chaînes de longueur nulle, les colonnes 6a, 5b et 6b montrent les méthodes correctes pour le faire. Notez également que n'importe lequel de ces tests peut être annulé si l'annulation indique une intention plus claire que l'utilisation de l'opération opposée. Par exemple: if ! [[ -n $var ]].

Si vous utilisez [, la clé est la clé pour éviter des résultats inattendus. En utilisant [[, ça n'a pas d'importance.

Les messages d'erreur supprimés sont "opérateur unaire attendu" ou "opérateur binaire attendu".

C'est le script qui a produit le tableau ci-dessus.

#!/bin/bash
# by Dennis Williamson
# 2010-10-06, revised 2010-11-10
# for http://stackoverflow.com/q/3869072
# designed to fit an 80 character terminal

dw=5    # description column width
w=6     # table column width

t () { printf '%-*s' "$w" " true"; }
f () { [[ $? == 1 ]] && printf '%-*s' "$w" " false" || printf '%-*s' "$w" " -err-"; }

o=/dev/null

echo '     | 1a    2a    3a    4a    5a    6a   | 1b    2b    3b    4b    5b    6b'
echo '     | [     ["    [-n   [-n"  [-z   [-z" | [[    [["   [[-n  [[-n" [[-z  [[-z"'
echo '-----+------------------------------------+------------------------------------'

while read -r d t
do
    printf '%-*s|' "$dw" "$d"

    case $d in
        unset) unset t  ;;
        space) t=' '    ;;
    esac

    [ $t ]        2>$o  && t || f
    [ "$t" ]            && t || f
    [ -n $t ]     2>$o  && t || f
    [ -n "$t" ]         && t || f
    [ -z $t ]     2>$o  && t || f
    [ -z "$t" ]         && t || f
    echo -n "|"
    [[ $t ]]            && t || f
    [[ "$t" ]]          && t || f
    [[ -n $t ]]         && t || f
    [[ -n "$t" ]]       && t || f
    [[ -z $t ]]         && t || f
    [[ -z "$t" ]]       && t || f
    echo

done <<'EOF'
unset
null
space
zero    0
digit   1
char    c
hyphn   -z
two     a b
part    a -a
Tstr    -n a
Fsym    -h .
T=      1 = 1
F=      1 = 2
T!=     1 != 2
F!=     1 != 1
Teq     1 -eq 1
Feq     1 -eq 2
Tne     1 -ne 2
Fne     1 -ne 1
EOF
361

Il vaut mieux utiliser le plus puissant[[ en ce qui concerne Bash.

Cas habituels

if [[ $var ]]; then   # var is set and it is not empty
if [[ ! $var ]]; then # var is not set or it is set to an empty string

Les deux constructions ci-dessus ont l'air propres et lisibles. Ils devraient suffire dans la plupart des cas.

Notez qu'il n'est pas nécessaire de citer les développements variables à l'intérieur de [[ car il n'y a aucun danger de division de mots et globbing .

Pour prévenir les plaintes légères de shellcheck à propos de [[ $var ]] et [[ ! $var ]], on pourrait utiliser le -n option.

Cas rares

Dans les rares cas où nous aurions à faire la distinction entre "être défini sur une chaîne vide" et "ne pas être défini du tout", nous pourrions utiliser ceux-ci:

if [[ ${var+x} ]]; then           # var is set but it could be empty
if [[ ! ${var+x} ]]; then         # var is not set
if [[ ${var+x} && ! $var ]]; then # var is set and is empty

Nous pouvons aussi utiliser le -v test:

if [[ -v var ]]; then             # var is set but it could be empty
if [[ ! -v var ]]; then           # var is not set
if [[ -v var && ! $var ]]; then   # var is set and is empty
if [[ -v var && -z $var ]]; then  # var is set and is empty

Articles connexes et documentation

Il existe de nombreux articles sur ce sujet. Voici quelques-uns:

14
codeforester

Voici quelques tests supplémentaires

Vrai si la chaîne n'est pas vide:

[ -n "$var" ]
[[ -n $var ]]
test -n "$var"
[ "$var" ]
[[ $var ]]
(( ${#var} ))
let ${#var}
test "$var"

Vrai si la chaîne est vide:

[ -z "$var" ]
[[ -z $var ]]
test -z "$var"
! [ "$var" ]
! [[ $var ]]
! (( ${#var} ))
! let ${#var}
! test "$var"
8
Steven Penny

La réponse correcte est la suivante:

if [[ -n $var ]] ; then
  blah
fi

Notez l'utilisation de la [[...]], qui gère correctement la citation des variables pour vous.

0
user2592126

utilisation case/esac tester

case "$var" in
  "") echo "zero length";;
esac
0
ghostdog74

Une façon alternative et peut-être plus transparente d'évaluer une variable env vide consiste à utiliser ...

  if [ "x$ENV_VARIABLE" != "x" ] ; then
      echo 'ENV_VARIABLE contains something'
  fi
0
user1310789