J'ai un tableau qui est rempli avec différents messages d'erreur pendant l'exécution de mon script.
J'ai besoin d'un moyen de vérifier si c'est vide ou non à 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?
=
s'agit d'un opérateur de chaîne. Il se trouve que cela fonctionne bien dans ce cas, mais j'utiliserais-eq
plutôt l' opérateur arithmétique approprié (juste au cas où je voudrais passer à-ge
ou-lt
, etc.).set -u
: "variable non liée" - si le tableau est vide.set -u;
foo=();
[ ${#foo[@]} -eq 0 ] && echo empty
. Si Iunset foo
, alors cela s’imprimefoo: unbound variable
, mais c’est différent: la variable tableau n’existe pas du tout, elle existe et est vide.set -u
- tant que vous avez déclaré votre variable en premier, cela fonctionne parfaitement.J'utilise généralement l'expansion arithmétique dans ce cas:
la source
(( ${#a} ))
(longueur du premier élément) fonctionnera également. Cependant, cela échoueraa=('')
, alors que(( ${#a[@]} ))
donné dans la réponse réussira.Vous pouvez également considérer le tableau comme une simple variable. De cette façon, juste en utilisant
ou en utilisant l'autre côté
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!)L'utilisation
[ -z "$array[@]" ]
n'est clairement pas une solution non plus. Ne pas spécifier les accolades essaie d'interpréter$array
comme une chaîne (il[@]
s'agit dans ce cas d'une chaîne littérale simple) et est donc toujours signalé comme étant faux: "la chaîne littérale est-elle[@]
vide?" Clairement pas.la source
[ -z "$array" ]
ou[ -n "$array" ]
ne fonctionne pas. Essayezarray=('' foo); [ -z "$array" ] && echo empty
, et il imprimeraempty
même s'ilarray
n'est clairement pas vide.[[ -n "${array[*]}" ]]
interpole l'intégralité du tableau en tant que chaîne, que vous vérifiez pour une longueur non nulle. Si vous considérezarray=("" "")
être vide, plutôt que d'avoir deux éléments vides, cela peut être utile.[[ -n " " ]]
est "vraie", ce qui est dommage. Votre commentaire est exactement ce que je veux faire.set -x
montre comment il se développe. Je suppose que je n'ai pas testé ce commentaire avant de poster. >. <Vous pouvez le faire fonctionner en définissantIFS=''
(enregistrez / restaurez-le autour de cette instruction), car le"${array[*]}"
développement sépare les éléments avec le premier caractère de IFS. (Ou espace si non défini). Mais " Si IFS est nul, les paramètres sont joints sans séparateurs intermédiaires " (docs pour $ * positional params, mais je suppose même pour les tableaux).J'ai vérifié avec
bash-4.4.0
:et
bash-4.1.5
:Dans ce dernier cas, vous avez besoin de la construction suivante:
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 la docs :Si vous n'en avez pas besoin, n'hésitez pas à en omettre une
:+${array[@]}
partie.Notez également qu'il est essentiel d'utiliser
[[
operator ici, avec[
vous obtenez:la source
-u
vous devriez réellement utiliser${array[@]+"${array[@]}"}
cf stackoverflow.com/a/34361807/1237617@
sûrement le. Vous pouvez utiliser l'*
extension de tableau comme[ "${array[*]}" ]
, n'est-ce pas? Pourtant,[[
fonctionne aussi très bien. Le comportement de ces deux éléments pour un tableau avec plusieurs chaînes vides est un peu surprenant. Les deux[ ${#array[*]} ]
et[[ "${array[@]}" ]]
sont faux pourarray=()
etarray=('')
mais vrais pourarray=('' '')
(deux chaînes vides ou plus). Si vous voulez une ou plusieurs chaînes vides pour que toutes donnent la valeur true, vous pouvez utiliser[ ${#array[@]} -gt 0 ]
. Si vous les vouliez tous faux, vous pourriez peut-être//
les faire sortir.[ "${array[*]}" ]
, mais si je rencontrais une telle expression, il serait plus difficile pour moi de comprendre ce que cela fait. Depuis[...]
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[*]}" ]
comme "vérifier si le résultat de l'interpolation de tous les éléments du tableau est une chaîne non vide".[ ${#array[*]} ]
, vous avez probablement voulu 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 ce dernier avec deux éléments, l'expression entre crochets' '
est complétée par une chaîne non vide. En ce qui concerne[[ ${array[@]} ]]
, ils pensent simplement (et à juste titre) que tout tableau de deux éléments est non vide.Si vous voulez détecter un tableau avec des éléments vides , comme
arr=("" "")
vide, identique àarr=()
Vous pouvez coller tous les éléments ensemble et vérifier si le résultat est zéro. (Construire une copie aplatie du contenu du tableau n'est pas idéal pour la performance si le tableau peut être très grand. Mais j'espère que vous n'utilisez pas bash pour de tels programmes ...)
Mais se
"${arr[*]}"
développe avec des éléments séparés par le premier caractère deIFS
. Donc, vous devez enregistrer / restaurer IFS et le faireIFS=''
pour que cela fonctionne, ou bien vérifiez que la longueur de la chaîne == # d'éléments de tableau - 1. (Un tableau d'n
éléments a desn-1
séparateurs). Pour régler ce problème, il est plus facile d’enrichir la concaténation de 1cas de test avec
set -x
Malheureusement , cela ne fonctionne pas pour
arr=()
:[[ 1 -ne 0 ]]
. Il est donc nécessaire de vérifier séparément les tableaux réellement vides.Ou avec
IFS=''
. Vous voudrez probablement sauvegarder / restaurer IFS au lieu d'utiliser un sous-shell, car vous ne pouvez pas obtenir facilement le résultat d'un sous-shell.exemple:
ne fonctionne avec
arr=()
- il est encore juste la chaîne vide.la source
[[ "${arr[*]}" = *[![:space:]]* ]]
, car je peux compter sur au moins un caractère non WS.arr=(" ")
.Dans mon cas, la deuxième réponse ne suffisait pas, car il pouvait y avoir des espaces. Je suis venu avec:
la source
echo | wc
semble inutilement inefficace comparé à l’utilisation de shell intégrés.[ ${#errors[@]} -eq 0 ];
afin de résoudre le problème des espaces? Je préférerais aussi le intégré.$#
étend à un nombre, et fonctionne bien même aprèsopts+=("")
. par exempleunset opts;
opts+=("");opts+=(" "); echo "${#opts[@]}"
et je reçois2
. Pouvez-vous montrer un exemple de quelque chose qui ne fonctionne pas?opts=("")
le mêmeopts=()
? Ce n'est pas un tableau vide, mais vous pouvez rechercher un tableau vide ou un premier élément vide avecopts=("");
[[ "${#opts[@]}" -eq 0 || -z "$opts" ]] && echo empty
. Notez que votre réponse actuelle dit "pas d'options" pouropts=("" "-foo")
, ce qui est totalement faux, et cela reproduit ce comportement. Vous pourriez,[[ -z "${opts[*]}" ]]
je suppose, interpoler tous les éléments du tableau en une chaîne plate qui-z
vérifie la longueur non nulle. Si cocher le premier élément est suffisant,-z "$opts"
fonctionne.Je préfère utiliser les doubles crochets:
la source