J'ai un tableau qui se remplit de différents messages d'erreur lors de l'exécution de mon script.
J'ai besoin d'un moyen de vérifier s'il 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 VAR normal 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?
Supposons que votre tableau soit $errors
, vérifiez simplement si le nombre d'éléments est nul.
if [ ${#errors[@]} -eq 0 ]; then
echo "No errors, hooray"
else
echo "Oops, something went wrong..."
fi
J'utilise généralement l'expansion arithmétique dans ce cas:
if (( ${#a[@]} )); then
echo not empty
fi
Vous pouvez également considérer le tableau comme une simple variable. De cette façon, en utilisant simplement
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 rapporteront le tableau comme vide, alors qu'il ne l'est clairement pas. (merci @musiphil!)
L'utilisation de [ -z "$array[@]" ]
N'est clairement pas une solution non plus. Ne pas spécifier de crochets essaie d'interpréter $array
Comme une 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?" Pas du tout.
Je l'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 vous faites set -eu
comme 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 simple (voir Commandes simples), une liste (voir Listes) ou une commande composée (voir Commandes composées) renvoie un état différent de zéro. Le shell ne se ferme pas si la commande qui échoue fait partie de la liste de commandes immédiatement après un mot clé while ou until, une partie du test dans une instruction if, une partie de toute commande exécutée dans un && ou || liste à l'exception de la commande suivant le && ou || final, toute commande dans un pipeline mais la dernière, ou si le statut de retour de la commande est inversé avec!. Si une commande composée autre qu'un sous-shell renvoie un état différent de zéro car une commande a échoué alors que -e était ignoré, le shell ne se ferme pas. Un trap sur ERR, s'il est défini, est exécuté avant la fermeture du shell.
Cette option s'applique à l'environnement Shell et à chaque environnement de sous-shell séparément (voir Environnement d'exécution de commandes) et peut entraîner la fermeture des sous-shells avant d'exécuter 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 et paramètres non définis autres que les paramètres spéciaux ‘@’ ou ‘*’ comme une erreur lors de l’expansion des paramètres. Un message d'erreur sera écrit dans l'erreur standard et un shell non interactif se fermera.
Si vous n'en avez pas besoin, n'hésitez pas à omettre :+${array[@]}
partie.
Notez également qu'il est essentiel d'utiliser [[
opérateur ici, avec [
vous obtenez:
$ 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
Si vous voulez détecter un tableau avec des éléments vides , comme arr=("" "")
comme vide, comme arr=()
Vous pouvez coller tous les éléments ensemble et vérifier si le résultat est de longueur nulle. (Construire une copie aplatie du contenu du tableau n'est pas idéal pour les performances si le tableau peut être très grand. Mais j'espère que vous n'utilisez pas bash pour des programmes comme ça ...)
Mais "${arr[*]}"
Se développe avec des éléments séparés par le premier caractère de IFS
. Vous devez donc enregistrer/restaurer IFS et faire IFS=''
Pour que cela fonctionne, ou bien vérifier que la longueur de chaîne == # des éléments du tableau - 1. (Un tableau d'éléments n
a n-1
Séparateurs). Pour gérer ce problème, il est plus facile de remplir la concaténation de 1
arr=("" "")
## Assuming default non-empty IFS
## TODO: also check for ${#arr[@]} -eq 0
concat="${arr[*]} " # n-1 separators + 1 space + array elements
[[ "${#concat}" -ne "${#arr[@]}" ]] && echo not empty array || echo empty array
cas de test avec set -x
### a non-empty element
$ arr=("" "x")
+ arr=("" "x")
$ concat="${arr[*]} "; [[ "${#concat}" -ne "${#arr[@]}" ]] && echo not empty array || echo empty array
+ concat=' x '
+ [[ 3 -ne 2 ]]
+ echo not empty array
not empty array
### 2 empty elements
$ arr=("" "")
+ arr=("" "")
$ concat="${arr[*]} "; [[ "${#concat}" -ne "${#arr[@]}" ]] && echo not empty array || echo empty array
+ concat=' '
+ [[ 2 -ne 2 ]]
+ echo empty array
empty array
Malheureusement, cela échoue pour arr=()
: [[ 1 -ne 0 ]]
. Vous devez donc d'abord vérifier séparément les tableaux vides.
Ou avec IFS=''
. Vous voudrez probablement enregistrer/restaurer IFS au lieu d'utiliser un sous-shell, car vous ne pouvez pas obtenir facilement un résultat d'un sous-shell.
# inside a () subshell so we don't modify our own IFS
(IFS='' ; [[ -n "${arr[*]}" ]] && echo not empty array || echo empty array)
exemple:
$ arr=("" "")
$ (IFS='' ; [[ -n "${arr[*]}" ]] && echo not empty array || echo empty array)
+ IFS=
+ [[ -n '' ]]
+ echo empty array
empty array
fonctionne avec arr=()
- c'est toujours juste la chaîne vide.
Je préfère utiliser des crochets doubles:
if [[ !${array[@]} ]]
then
echo "Array is empty"
else
echo "Array is not empty"
fi
Supports doubles: https://stackoverflow.com/questions/669452/is-preferable-over-in-bash
Dans mon cas, la deuxième réponse n'était pas suffisante 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