Est-il possible de lire le dernier élément d'un tableau avec bash?

68

Si j'ai un tableau avec 5 éléments, par exemple:

[a][b][c][d][e]

En utilisant echo ${myarray[4]}je peux voir ce qu’il contient.

Mais que se passe-t-il si je ne connais pas le nombre d'éléments dans un tableau donné? Existe-t-il un moyen de lire le dernier élément d'un tableau de longueur inconnue? ie le premier élément lisant de droite à gauche pour un tableau?

Je voudrais savoir comment faire cela à Bash.

3kstc
la source
$@n'est pas exactement un tableau (ne peut pas être souscrit). Pour cela, voir Obtenir le dernier argument transmis à un script shell .
Tom Hale

Réponses:

89

Vous pouvez simplement utiliser un index négatif ${myarray[-1]} pour obtenir le dernier élément. Vous pouvez faire la même chose pour l'avant-dernier, et ainsi de suite; dans Bash:

Si l'indice utilisé pour référencer un élément d'un tableau indexé est évalué à un nombre inférieur à zéro, il est interprété comme relatif à un indice supérieur à l'indice maximal du tableau. Par conséquent, les index négatifs comptent à partir de la fin du tableau. index de -1 fait référence au dernier élément.

La même chose fonctionne également pour la cession. Quand il dit "expression", cela signifie vraiment une expression; vous pouvez y écrire n'importe quelle expression arithmétique pour calculer l'index, y compris celle qui calcule en utilisant ${#myarray[@]}explicitement la longueur du tableau .

Michael Homer
la source
2
Vous pouvez le faire dans kshet zshaussi bien.
Janis
5
Avec zshcependant, par des réseaux par défaut sont 1-indexés, à la différence bashet kshoù ils sont 0 indexées.
Stephen Kitt
2
Oui bien sûr; la réponse courte à cette question ne change pas, mais depuis que le formulaire long a été mentionné, j’ai jugé nécessaire de souligner la différence de comportement.
Stephen Kitt
22
L'indice négatif ne fonctionne que dans les versions 4.3 et supérieures.
jeudi
10
La version de Bash incluse dans Mac OS X à partir de la version 10.11.5 n’est que 3.2, elle ne fonctionne donc pas sur les Mac.
Doktor J
45

Bash moderne (v4.1 ou mieux)

Vous pouvez lire le dernier élément à l'index -1:

$ a=(a b c d e f)
$ echo ${a[-1]}
f

La prise en charge de l'accès aux tableaux indexés numériquement à partir de la fin à l'aide des index négatifs a démarré avec bash version 4.1-alpha .

Ancien bash (v4.0 ou antérieur)

Vous devez obtenir la longueur du tableau à partir de ${#a[@]}puis soustraire un pour obtenir le dernier élément:

$ echo ${a[${#a[@]}-1]}
f

Puisque bash considère les indices de tableau comme une expression arithmétique, il n’est pas nécessaire d’utiliser une notation supplémentaire, telle que $((...)), pour forcer l’évaluation arithmétique.

John1024
la source
le dernier ne fonctionne pas pour moi; J'utilise Bash v4.1.2 (1): au lieu d'imprimer le dernier élément, il affiche simplement le tableau entier.
Alexej Magura
La réponse de @ cuonglm fonctionne cependant.
Alexej Magura
La réponse serait encore meilleure si vous pouviez vous qualifier modernavec une version.
Samveen
1
Exactement ce qui était nécessaire pour que la réponse soit parfaite.
Samveen
1
Merci pour ça. J'utilisais echo $ {a [$ (($ {# a [@]} - 1]))} parce que je ne savais pas que "bash traite les indices de tableau comme une expression arithmétique".
Bruno Bronosky
15

bashl’affectation de tableau, la référence, la suppression avec un indice négatif n’ont été ajoutées que dans bash 4.3 . Avec l'ancienne version de bash, vous pouvez utiliser l'expression dans l'indexarray[${#array[@]-1}]

Vous pouvez également utiliser une version plus ancienne de bash(bash 3.0 ou supérieure):

$ a=([a] [b] [c] [d] [e])
$ printf %s\\n "${a[@]:(-1)}"
[e]

ou:

$ printf %s\\n "${a[@]: -1}"
[e]

En utilisant un décalage négatif, vous devez séparer :avec -pour éviter toute confusion avec l' :-extension.

cuonglm
la source
1
Faites ça "${a[@]: -1}"et ça marchera (à côté bashet zshaussi) dans ksh.
Janis
La documentation Kornshell ( www2.research.att.com/sw/download/man/man1/ksh.html ) le spécifie complètement. (Je n'ai pas inspecté les docs de zshor bash; mais je l'ai testé dans les trois coques.)
Janis le
@Janis: relisez la documentation bash, il a également mentionné celui-ci également. Merci encore.
jeudi
4

tableau

Les alternatives les plus anciennes à bash (depuis bash 3.0+) sont:

$ a=(aa bb cc dd ee)
$ echo "${a[@]:(-1)}   ${a[@]: -1}   ${a[@]:(~0)}   ${a[@]:~0}"
ee   ee   ee   ee

L'espace est requis pour éviter l'interprétation de :suivi d'un moins -comme développement de "${var:-abc}"(Utiliser les valeurs par défaut).

Le ~est une négation arithmétique au niveau du bit (équivalent à son complément ou retournement de tous les bits ). De l'homme bash:

EVALUATION ARITHMETIQUE

      ! ~         logical and bitwise negation  

Depuis bash-4.2 + aussi:

$ echo "${a[-1]}   ${a[(~0)]}"
ee   ee

Depuis bash 5.0+ aussi:

$ echo "${a[~0]}"
ee

Pour toutes les versions de bash (ancien bash):

$ echo "${a[   ${#a[@]}-1   ]}"    # spaces added **only** for readability
ee

@

Pour les arguments de position (depuis bash 2.01):

$ set aa bb cc dd ee
$ echo "${@:(-1)} ${@:~0} ${@: -1} ${@:$#}   ${!#}"
ee ee ee   ee

Une solution portable pour tous les shells consiste à utiliser eval:

eval printf '"%s\n"' \"\${$#}\"
Isaac
la source
Avez-vous une référence pour la syntaxe bash 5+? J'ai cherché toutes les 58 occurrences ~dans le manuel et je ne l'ai pas vu.
Tom Hale
... et comment fais-tu avec $@? bash: ${@[@]:(-1)}: bad substitution
Tom Hale
1
Oui, il y a une man bashréférence (cochez la réponse développée dans le @ titre). @TomHale
Isaac
1
Le @n'est pas un tableau (enfin, pas tout à fait un tableau ) dans bash et il n'accepte pas l'indice ( []) pour les arguments individuels. Vous devez utiliser ${@:(-1)}ou équivalent. Vérifiez l'entrée élargie au @titre. @TomHale
Isaac
-2

Aussi, vous pouvez faire ceci:

$ a=(a b c d e f)
$ echo ${a[$(expr ${#a[@]} - 1)]}

Résultat:

$ f

Ce que vous faites, c'est obtenir le nombre total d'éléments dans le tableau et soustraire -1, car vous obtenez tous les éléments, sans partir de l'index de tableau qui est 0.

Javier Salas
la source