J'écris un script bash qui a set -u
, et j'ai un problème avec l'expansion de tableau vide: bash semble traiter un tableau vide comme une variable non définie pendant l'expansion:
$ set -u
$ arr=()
$ echo "foo: '${arr[@]}'"
bash: arr[@]: unbound variable
( declare -a arr
n'aide pas non plus.)
Une solution courante à cela est d'utiliser à la ${arr[@]-}
place, substituant ainsi une chaîne vide au lieu du tableau vide ("indéfini"). Cependant, ce n'est pas une bonne solution, car maintenant vous ne pouvez pas discerner entre un tableau contenant une seule chaîne vide et un tableau vide. (@ -expansion est spécial en bash, il se dilate "${arr[@]}"
dans "${arr[0]}" "${arr[1]}" …
, ce qui en fait un outil idéal pour la construction de lignes de commande.)
$ countArgs() { echo $#; }
$ countArgs a b c
3
$ countArgs
0
$ countArgs ""
1
$ brr=("")
$ countArgs "${brr[@]}"
1
$ countArgs "${arr[@]-}"
1
$ countArgs "${arr[@]}"
bash: arr[@]: unbound variable
$ set +u
$ countArgs "${arr[@]}"
0
Existe-t-il donc un moyen de contourner ce problème, autre que de vérifier la longueur d'un tableau dans un if
(voir l'exemple de code ci-dessous), ou de désactiver le -u
paramètre pour ce petit morceau?
if [ "${#arr[@]}" = 0 ]; then
veryLongCommandLine
else
veryLongCommandLine "${arr[@]}"
fi
Mise à jour:bugs
balise supprimée en raison de l'explication d'ikegami.
"${arr[@]}"
. Est-ce que je manque quelque chose? D'après ce que je peux voir, cela fonctionne au moins5.x
.Selon la documentation,
Aucun indice n'a reçu de valeur, le tableau n'est donc pas défini.
Mais alors que la documentation suggère qu'une erreur est appropriée ici, ce n'est plus le cas depuis 4.4 .
Il existe une condition que vous pouvez utiliser en ligne pour obtenir ce que vous voulez dans les anciennes versions: utilisez à la
${arr[@]+"${arr[@]}"}
place de"${arr[@]}"
.Testé avec bash 4.2.25 et 4.3.11.
la source
[@]+
fait réellement et pourquoi la seconde${arr[@]}
ne causera pas d'erreur non liée.${parameter+word}
ne se développe queword
si elleparameter
n'est pas désactivée.${arr+"${arr[@]}"}
est plus court et semble fonctionner aussi bien.unset arr
,arr[1]=a
,args ${arr+"${arr[@]}"}
Contreargs ${arr[@]+"${arr[@]}"}
+
expansion ne se produit pas (à savoir, un tableau vide), l'expansion est remplacée par rien , ce qui est exactement ce à quoi un tableau vide se développe.:+
est dangereux car il traite également un('')
tableau à un seul élément comme non défini et se développe de la même manière en rien, perdant la valeur.La réponse acceptée de @ ikegami est subtilement fausse! L'incantation correcte est
${arr[@]+"${arr[@]}"}
:la source
bash-4.4.23
:arr=('') && countArgs "${arr[@]:+${arr[@]}}"
produit1
. Mais la${arr[@]+"${arr[@]}"}
forme permet de différencier les valeurs vides / non vides en ajoutant / ne ajoutant pas de deux-points.arr=('') && countArgs ${arr[@]:+"${arr[@]}"}
->0
,arr=('') && countArgs ${arr[@]+"${arr[@]}"}
->1
.Il s'avère que la gestion des tableaux a été modifiée dans la dernière version (2016/09/16) de bash 4.4 (disponible dans Debian Stretch, par exemple).
L'expansion des tableaux vides n'émet plus d'avertissement
la source
bash-4.4.12
"${arr[@]}"
cela suffirait.cela peut être une autre option pour ceux qui préfèrent ne pas dupliquer arr [@] et sont d'accord pour avoir une chaîne vide
tester:
la source
for
cela se terminerait par une seule chaîne vide lorsque le tableau est indéfini / défini comme vide, où vous voudrez peut-être le corps de la boucle pour ne pas s'exécuter si le tableau n'est pas défini.${arr[@]+"${arr[@]}"}
,, préserve correctement l'état du tableau vide.La réponse de @ ikegami est correcte, mais je considère que la syntaxe est
${arr[@]+"${arr[@]}"}
épouvantable. Si vous utilisez de longs noms de variables de tableau, cela commence à sembler spaghetti plus rapidement que d'habitude.Essayez plutôt ceci:
Il semble que l'opérateur de tranche de tableau Bash soit très indulgent.
Alors pourquoi Bash a-t-il rendu la gestion du cas de bord des tableaux si difficile? Soupir. Je ne peux pas garantir que votre version autorisera un tel abus de l'opérateur de tranche de tableau, mais cela fonctionne parfaitement pour moi.
Attention: j'utilise
GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
votre kilométrage peut varier.la source
"${arr[@]:0}"
donne-bash: arr[@]: unbound variable
.arr=("_dummy_")
et d'utiliser l'extension${arr[@]:1}
partout. Ceci est mentionné dans d'autres réponses, faisant référence aux valeurs sentinelles.Incohérence "intéressante" en effet.
En outre,
Bien que je sois d'accord pour dire que le comportement actuel n'est peut-être pas un bogue au sens où l'explique @ikegami, IMO nous pourrions dire que le bogue est dans la définition (de "set") elle-même, et / ou dans le fait qu'il est appliqué de manière incohérente. Le paragraphe précédent de la page de manuel dit
ce qui est tout à fait cohérent avec ce qu'il dit sur l'expansion des paramètres de position dans
"$@"
. Non pas qu'il n'y ait pas d'autres incohérences dans les comportements des tableaux et des paramètres de position ... mais pour moi, rien n'indique que ce détail devrait être incohérent entre les deux.Continuant,
Alors
arr[]
n'est-il pas si indépendant que nous ne pouvons pas obtenir un nombre de ses éléments (0), ou une liste (vide) de ses clés? Pour moi, ils sont sensés et utiles - la seule valeur aberrante semble être l' expansion${arr[@]}
(et${arr[*]}
).la source
Je complète les réponses de @ ikegami (acceptées) et de @ kevinarpe (également bonnes).
Vous pouvez faire
"${arr[@]:+${arr[@]}}"
pour contourner le problème. Le côté droit (c'est-à-dire après:+
) fournit une expression qui sera utilisée au cas où le côté gauche n'est pas défini / nul.La syntaxe est obscure. Notez que le côté droit de l'expression subira une expansion des paramètres, donc une attention particulière doit être accordée à la cohérence des guillemets.
Comme le mentionne @kevinarpe, une syntaxe moins arcanique consiste à utiliser la notation de tranche de tableau
${arr[@]:0}
(sur les versions Bash>= 4.4
), qui s'étend à tous les paramètres, à partir de l'index 0. Elle ne nécessite pas non plus autant de répétition. Cette extension fonctionne indépendamment deset -u
, vous pouvez donc l'utiliser à tout moment. La page de manuel indique (sous Extension des paramètres ):Voici l'exemple fourni par @kevinarpe, avec une mise en forme alternative pour mettre la sortie en évidence:
Ce comportement varie selon les versions de Bash. Vous avez peut-être également remarqué que l'opérateur de longueur
${#arr[@]}
évaluera toujours à0
pour les tableaux vides, indépendamment deset -u
, sans provoquer une 'erreur de variable non liée'.la source
:0
idiome échoue dans Bash 4.2, ce n'est donc pas une approche sûre. Voyez ma réponse .Voici quelques façons de faire quelque chose comme ça, une en utilisant des sentinelles et une autre en utilisant des appendices conditionnels:
la source
Incohérence intéressante; cela vous permet de définir quelque chose qui n'est "pas considéré comme défini" mais qui apparaît dans la sortie de
declare -p
MISE À JOUR: comme d'autres l'ont mentionné, corrigé dans la version 4.4 publiée après la publication de cette réponse.
la source
echo ${arr[@]}
(mais avant Bash 4.4, vous verrez toujours une erreur).echo $arr[@]
vous-même, vous auriez vu que le message d'erreur est différent.Le moyen le plus simple et le plus compatible semble être:
la source