Gibt es eine Möglichkeit, das letzte Element eines Arrays mit bash zu lesen?

68

Wenn ich ein Array mit 5 Elementen habe, zum Beispiel:

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

Mit echo ${myarray[4]}kann ich sehen, was es hält.

Aber was ist, wenn ich die Anzahl der Elemente in einem bestimmten Array nicht kenne? Gibt es eine Möglichkeit, das letzte Element eines Arrays unbekannter Länge zu lesen? dh das erste Element, das für ein Array von rechts nach links liest?

Ich würde gerne wissen, wie man das in bash macht.

3kstc
quelle
$@ist nicht gerade ein Array (kann nicht subskribiert werden). Informationen hierzu finden Sie unter Abrufen des letzten an ein Shell-Skript übergebenen Arguments .
Tom Hale

Antworten:

89

Sie können einfach einen negativen Index verwenden ${myarray[-1]} , um das letzte Element abzurufen. Sie können dasselbe für den vorletzten Schritt tun und so weiter. in Bash:

Wenn der Index, der zum Verweisen auf ein Element eines indizierten Arrays verwendet wird, eine Zahl kleiner als Null ergibt, wird er als relativ zu eins interpretiert, die größer als der maximale Index des Arrays ist, sodass negative Indizes vom Ende des Arrays an zurückzählen index von -1 bezieht sich auf das letzte Element.

Das gleiche gilt auch für die Zuordnung. Wenn es "Ausdruck" sagt, bedeutet es wirklich einen Ausdruck; Sie können dort einen beliebigen arithmetischen Ausdruck eingeben, um den Index zu berechnen, einschließlich eines Ausdrucks, der ${#myarray[@]}explizit anhand der Länge des Arrays berechnet wird .

Michael Homer
quelle
2
Sie können das auch in kshund tun zsh.
Janis
5
Mit zshobwohl standardmäßig Arrays 1-indiziert sind, im Gegensatz zu bashund kshwo sie sind 0-indiziert.
Stephen Kitt
2
Ja natürlich; Die kurze Antwort auf diese Frage ändert sich nicht, aber da die lange Form erwähnt wurde, hielt ich es für notwendig, auf den Unterschied im Verhalten hinzuweisen.
Stephen Kitt
22
Der negative Index funktioniert nur in Bash 4.3 und höher.
Cuonglm
10
Die Version von Bash, die in Mac OS X ab Version 10.11.5 enthalten ist, ist nur 3.2, daher funktioniert dies nicht auf Macs.
Doktor J
45

Modern bash (v4.1 oder besser)

Sie können das letzte Element am Index lesen -1:

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

Unterstützung für den Zugriff auf numerisch indizierte Arrays von Anfang an unter Verwendung negativer Indizes, die mit der Bash-Version 4.1-alpha gestartet wurden .

Ältere Bash (v4.0 oder früher)

Sie müssen die Array-Länge von erhalten ${#a[@]}und dann eine subtrahieren, um das letzte Element zu erhalten:

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

Da Bash Array-Indizes als arithmetischen Ausdruck behandelt, ist keine zusätzliche Notation erforderlich, z. B. $((...))um die arithmetische Auswertung zu erzwingen.

John1024
quelle
der letzte funktioniert bei mir nicht; Ich verwende Bash v4.1.2 (1): Anstatt das letzte Element auszudrucken, wird nur das gesamte Array ausgedruckt.
Alexej Magura
@ Cuonglms Antwort funktioniert jedoch.
Alexej Magura
Die Antwort wäre noch besser, wenn Sie sich modernmit einer Version qualifizieren könnten .
Samveen
1
Genau das, was benötigt wurde, um die Antwort zu perfektionieren.
Samveen,
1
Danke dafür. Ich habe echo $ {a [$ (($ {# a [@]} - 1])} verwendet, weil ich nicht wusste, dass "bash Array-Indizes als arithmetischen Ausdruck behandelt".
Bruno Bronosky
15

bashArrayzuordnung, Referenz, Unset mit negativem Index wurden erst in Bash 4.3 hinzugefügt . In älteren Versionen von bashkönnen Sie den Ausdruck im Index verwendenarray[${#array[@]-1}]

Eine andere Möglichkeit, auch mit älteren Versionen von bash(bash 3.0 oder besser) zu arbeiten:

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

oder:

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

Mit negativen Offset, müssen Sie trennen :mit -der Verwechslung zu vermeiden :-Expansion.

cuonglm
quelle
1
Machen Sie das "${a[@]: -1}"und es wird (neben bashund zsh) auch in ksh.
Janis
In den Kornshell-Dokumenten ( www2.research.att.com/sw/download/man/man1/ksh.html ) ist dies vollständig angegeben. (Ich habe die Dokumente von zshoder nicht überprüft bash, aber ich habe sie in allen drei Shells getestet.)
Janis,
@Janis: Lies die Bash-Dokumentation noch einmal durch, sie wurde auch darüber erwähnt. Danke noch einmal.
Cuonglm
4

Array

Die ältesten Alternativen in bash (seit bash 3.0+) sind:

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

Das Leerzeichen ist erforderlich, um die Interpretation von :gefolgt von einem Minus -als Erweiterung von "${var:-abc}"(Use Default Values) zu vermeiden .

Das ~ist eine arithmetische bitweise Negation (entspricht dem eigenen Komplement oder spiegeln Sie alle Bits ). Von Mann Bash:

ARITHMETISCHE BEWERTUNG

      ! ~         logical and bitwise negation  

Seit bash-4.2 + auch:

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

Seit bash 5.0+ auch:

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

Für alle Bash-Versionen (ältere Bash):

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

@

Für Positionsargumente (seit Bash 2.01):

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

Eine tragbare Lösung für alle Shells ist die Verwendung von eval:

eval printf '"%s\n"' \"\${$#}\"
Isaac
quelle
Haben Sie eine Referenz für die Bash 5+ -Syntax? Ich habe alle 58 Instanzen von ~im Handbuch durchsucht und es nicht gesehen.
Tom Hale
... und wie machst du das $@? bash: ${@[@]:(-1)}: bad substitution
Tom Hale
1
Ja, es gibt einen man bashVerweis (überprüfen Sie die erweiterte Antwort unter @ title). @TomHale
Isaac
1
Das @ist kein Array (also kein vollständiges Array ) in der Bash und akzeptiert den Index ( []) für einzelne Argumente nicht. Sie müssen verwenden ${@:(-1)}oder gleichwertig. Überprüfen Sie den erweiterten Eintrag im @Titel. @TomHale
Isaac
-2

Auch das können Sie tun:

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

Ergebnis:

$ f

Was Sie tun, ist, die gesamte Anzahl der Elemente im Array abzurufen und -1 zu subtrahieren, da Sie alle Elemente abrufen, und nicht ab dem Arrayindex 0 beginnen.

Javier Salas
quelle