Question Vérifier si le tableau est vide dans Bash


J'ai un tableau qui se remplit de différents messages d'erreur pendant l'exécution de mon script.

J'ai besoin d'un moyen de vérifier si elle est vide ou pas à la fin du script et de prendre une action spécifique si c'est le cas.

J'ai déjà essayé de le traiter comme un revendeur à valeur normale et d'utiliser -z pour le vérifier, mais cela ne semble pas fonctionner. Existe-t-il un moyen de vérifier si un tableau est vide ou non dans Bash?

Merci


82
2018-02-11 03:59


origine




Réponses:


En supposant que votre tableau est $errors, vérifiez que le nombre d’éléments est égal à zéro.

if [ ${#errors[@]} -eq 0 ]; then
    echo "No errors, hooray"
else
    echo "Oops, something went wrong..."
fi

113
2018-02-11 04:10



Veuillez noter que = est un opérateur de chaîne. Il se trouve que cela fonctionne bien dans ce cas, mais j'utiliserais le bon opérateur arithmétique -eq au lieu de cela (juste au cas où je voudrais passer à -ge ou -lt, etc.). - musiphil
Ne fonctionne pas avec set -u: "variable non liée" - si le tableau est vide. - Igor
@Igor: Fonctionne pour moi dans Bash 4.4. set -u;  foo=();  [ ${#foo[@]} -eq 0 ] && echo empty. Si je unset foo, puis il imprime foo: unbound variable, mais c'est différent: la variable tableau n'existe pas du tout, plutôt qu'exister et être vide. - Peter Cordes
Également testé dans Bash 3.2 (OSX) lors de l’utilisation de set -u - tant que vous avez déclaré votre variable en premier, cela fonctionne parfaitement. - zeroimpl


Vous pouvez également considérer le tableau comme une simple variable. De cette façon, juste en utilisant

if [ -z "$array" ]; then
    echo "Array empty"
else
    echo "Array non empty"
fi

ou en utilisant l'autre côté

if [ -n "$array" ]; then
    echo "Array non empty"
else
    echo "Array empty"
fi

Le problème avec cette solution est que si un tableau est déclaré comme ceci: array=('' foo). Ces vérifications indiqueront que le tableau est vide, alors que ce n'est clairement pas le cas. (merci @musiphil!)

En utilisant [ -z "$array[@]" ] n'est clairement pas une solution non plus. Ne pas spécifier les accolades tente d'interpréter $array sous forme de chaîne ([@] est dans ce cas une chaîne littérale simple) et est donc toujours signalé comme faux: "est la chaîne littérale [@] vide? "Clairement pas.


6
2018-06-23 10:29



[ -z "$array" ] ou [ -n "$array" ] ne fonctionne pas. Essayer array=('' foo); [ -z "$array" ] && echo empty, et il imprimera empty même si array est clairement pas vide. - musiphil
[[ -n "${array[*]}" ]] interpole tout le tableau en tant que chaîne, que vous vérifiez pour une longueur non nulle. Si vous considérez array=("" "") être vide, plutôt que d'avoir deux éléments vides, cela pourrait être utile. - Peter Cordes


J'utilise généralement l'expansion arithmétique dans ce cas:

if (( ${#a[@]} )); then
    echo not empty
fi

3
2017-08-02 06:04



Agréable et propre! Je l'aime. Je note également que si le premier élément du tableau est toujours non vide, (( ${#a} )) (longueur du premier élément) fonctionnera également. Cependant, cela échouera sur a=(''), tandis que (( ${#a[@]} )) donné dans la réponse va réussir. - cxw


J'ai vérifié avec bash-4.4.0:

#!/usr/bin/env bash
set -eu
check() {
    if [[ ${array[@]} ]]; then
        echo not empty
    else
        echo empty
    fi
}
check   # empty
array=(a b c d)
check   # not empty
array=()
check   # empty

et bash-4.1.5:

#!/usr/bin/env bash
set -eu
check() {
    if [[ ${array[@]:+${array[@]}} ]]; then
        echo non-empty
    else
        echo empty
    fi
}
check   # empty
array=(a b c d)
check   # not empty
array=()
check   # empty

Dans ce dernier cas, vous avez besoin de la construction suivante:

${array[@]:+${array[@]}}

pour qu'il n'échoue pas sur un tableau vide ou non défini. C'est si tu fais set -eu comme je le fais d'habitude. Cela permet une vérification d'erreur plus stricte. De les docs:

-e

Quittez immédiatement si un pipeline (voir Pipelines), qui peut consister en une seule commande (voir Commandes simples), une liste (voir Listes) ou une commande composée (voir Commandes composées) renvoie un statut différent de zéro. Le shell ne se ferme pas si la commande qui échoue fait partie de la liste de commandes suivant immédiatement un mot-clé while ou Until, une partie du test dans une instruction if, une partie d'une commande exécutée dans un && ou || liste sauf la commande suivant le && ou || final, toutes les commandes d’un pipeline sauf le dernier ou si le statut de retour de la commande est inversé avec!. Si une commande composée autre qu'un sous-shell renvoie un statut différent de zéro car une commande a échoué alors que l'option -e était ignorée, le shell ne se ferme pas. Une interruption sur ERR, si définie, est exécutée avant la sortie du shell.

Cette option s'applique à l'environnement shell et à chaque environnement de sous-shell séparément (voir Environnement d'exécution des commandes), et peut entraîner la fermeture des sous-shell avant l'exécution de toutes les commandes du sous-shell.

Si une commande composée ou une fonction shell s'exécute dans un contexte où -e est ignoré, aucune des commandes exécutées dans la commande composée ou le corps de la fonction ne sera affectée par le paramètre -e, même si -e est défini et qu'une commande renvoie un état d'échec. Si une commande composée ou une fonction shell définit -e lors de l'exécution dans un contexte où -e est ignoré, ce paramètre n'aura aucun effet tant que la commande composée ou la commande contenant l'appel de fonction ne sera pas terminée.

-u

Traitez les variables non définies et les paramètres autres que les paramètres spéciaux «@» ou «*» comme une erreur lors de l’extension des paramètres. Un message d'erreur sera écrit sur l'erreur standard et un shell non interactif se fermera.

Si vous n'en avez pas besoin, n'hésitez pas à l'omettre :+${array[@]} partie.

Notez également qu'il est essentiel d'utiliser [[ opérateur ici, avec [ vous recevez:

$ cat 1.sh
#!/usr/bin/env bash
set -eu
array=(a b c d)
if [ "${array[@]}" ]; then
    echo non-empty
else
    echo empty
fi

$ ./1.sh
_/1.sh: line 4: [: too many arguments
empty

2
2017-12-04 14:58



Avec -u vous devriez réellement utiliser ${array[@]+"${array[@]}"} cf stackoverflow.com/a/34361807/1237617 - Jakub Bochenski
@JakubBochenski De quelle version de bash parlez-vous? gist.github.com/x-yuri/d933972a2f1c42a49fc7999b8d5c50b9 - x-yuri
Le problème dans l'exemple des crochets simples est le @sûrement. Vous pourriez utiliser * l'expansion de la matrice comme [ "${array[*]}" ], ne pourrais tu pas? Encore, [[ fonctionne aussi très bien. Le comportement de ces deux éléments pour un tableau avec plusieurs chaînes vides est un peu surprenant. Tous les deux [ ${#array[*]} ] et [[ "${array[@]}" ]] sont faux pour array=() et array=('') mais vrai pour array=('' '') (deux ou plusieurs chaînes vides). Si vous voulez une ou plusieurs chaînes vides pour que tout donne true, vous pouvez utiliser [ ${#array[@]} -gt 0 ]. Si vous les vouliez tous faux, vous pourriez peut-être // les sortir. - eisd
@eisd je pourrais utiliser [ "${array[*]}" ], mais si je rencontrais une telle expression, il me serait plus difficile de comprendre ce qu’elle fait. Puisque [...] fonctionne en termes de chaînes sur le résultat de l'interpolation. Par opposition à [[...]], qui peut être conscient de ce qui a été interpolé. C'est-à-dire qu'il peut savoir qu'il a été passé un tableau. [[ ${array[@]} ]] me lit comme "vérifier si le tableau est non vide", tandis que [ "${array[*]}" ] as "vérifier si le résultat de l'interpolation de tous les éléments du tableau est une chaîne non vide". - x-yuri
... En ce qui concerne le comportement avec deux chaînes vides, cela ne me surprend pas du tout. Ce qui est surprenant, c'est le comportement avec une chaîne vide. Mais raisonnablement raisonnable. En ce qui concerne [ ${#array[*]} ], tu voulais probablement dire [ "${array[*]}" ], puisque le premier est vrai pour un nombre quelconque d’éléments. Parce que le nombre d'éléments est toujours une chaîne non vide. En ce qui concerne le dernier avec deux éléments, l’expression entre crochets s’étend à ' ' qui est une chaîne non vide. Pour ce qui est de [[ ${array[@]} ]], ils pensent juste (et à juste titre) que tout tableau de deux éléments est non vide. - x-yuri


Dans mon cas, le deuxième réponse n'était pas suffisant car il pouvait y avoir des espaces blancs. Je suis venu avec:

if [ "$(echo -ne ${opts} | wc -m)" -eq 0 ]; then
  echo "No options"
else
  echo "Options found"
fi

0
2018-02-17 19:54



echo | wc semble inutilement inefficace comparé à l’utilisation de shell intégrés. - Peter Cordes
Pas sûr si je comprends @PeterCordes, puis-je modifier la deuxième réponse? ' [ ${#errors[@]} -eq 0 ]; de manière à contourner le problème des espaces? Je préférerais aussi le intégré. - Micha
Comment les espaces posent-ils un problème? $# se développe en un nombre, et fonctionne bien même après opts+=(""). par exemple. unset opts;  opts+=("");opts+=(" "); echo "${#opts[@]}" et je reçois 2. Pouvez-vous montrer un exemple de quelque chose qui ne fonctionne pas? - Peter Cordes
Il y a longtemps. IIRC la source d'origine a toujours imprimé au moins "". Ainsi, pour opts = "" ou opts = (""), j'avais besoin de 0, et non de 1, en ignorant la nouvelle ligne ou la chaîne vide. - Micha
Ok, alors il faut soigner opts=("") le même que opts=()? Ce n'est pas un tableau vide, mais vous pouvez rechercher un tableau vide ou un premier élément vide avec opts=("");  [[ "${#opts[@]}" -eq 0 || -z "$opts" ]] && echo empty. Notez que votre réponse actuelle indique "pas d’option" pour opts=("" "-foo"), ce qui est totalement faux, et cela reproduit ce comportement. Vous pourriez [[ -z "${opts[*]}" ]] Je suppose, pour interpoler tous les éléments du tableau dans une chaîne plate, qui -z vérifie la longueur non nulle.  Si la vérification du premier élément est suffisante, -z "$opts" travaux. - Peter Cordes


Je préfère utiliser les doubles crochets:

if [[ !${array[@]} ]]
then
    echo "Array is empty"
else
    echo "Array is not empty"
fi

Double crochets: https://stackoverflow.com/questions/669452/is-prepreable-over-in-bash


0
2017-11-04 06:40