Esiste un modo per leggere l'ultimo elemento di un array con bash?


68

Se ho un array con 5 elementi, ad esempio:

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

Usando echo ${myarray[4]}posso vedere cosa contiene.

Ma cosa succede se non sapessi il numero di elementi in un determinato array? Esiste un modo per leggere l'ultimo elemento di una matrice di lunghezza sconosciuta? cioè il primo elemento che legge da destra a sinistra per qualsiasi array?

Vorrei sapere come fare in bash.


$@non è esattamente un array (non può essere sottoscritto). Per questo, vedi Ottenere l'ultimo argomento passato a uno script di shell .
Tom Hale,

Risposte:


89

Puoi semplicemente usare un indice negativo ${myarray[-1]} per ottenere l'ultimo elemento. Puoi fare la stessa cosa per il penultimo, e così via; in Bash:

Se il pedice utilizzato per fare riferimento a un elemento di un array indicizzato restituisce un numero inferiore a zero, viene interpretato come relativo a uno maggiore dell'indice massimo dell'array, quindi gli indici negativi contano alla fine dell'array e un indice di -1 si riferisce all'ultimo elemento.

Lo stesso vale anche per il compito. Quando dice "espressione" significa davvero un'espressione; è possibile scrivere in qualsiasi espressione aritmetica per calcolare l'indice, incluso uno che calcola ${#myarray[@]}esplicitamente la lunghezza dell'array .


2
È possibile farlo in kshe zshpure.
Janis,

5
Con zshse, per matrici di default sono 1-indicizzati, a differenza bashe kshdove sono 0-indicizzati.
Stephen Kitt,

2
Sì, naturalmente; la risposta breve a questa domanda non cambia, ma poiché è stata menzionata la forma lunga, ho pensato che fosse necessario sottolineare la differenza di comportamento lì.
Stephen Kitt,

22
L'indice negativo funziona solo nella bash 4.3 e successive.
cuonglm,

10
La versione di Bash inclusa in Mac OS X almeno dalla v10.11.5 è solo 3.2, quindi non funziona sui Mac.
Doktor J,

45

Bash moderno (v4.1 o superiore)

Puoi leggere l'ultimo elemento all'indice -1:

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

Il supporto per l'accesso alle matrici a indicizzazione numerica dalla fine usando indici negativi è iniziato con la versione 4.1-alpha di bash .

Bash precedente (v4.0 o precedente)

È necessario ottenere la lunghezza dell'array ${#a[@]}e quindi sottrarne uno per ottenere l'ultimo elemento:

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

Dal momento che bash tratta gli indici di array come un'espressione aritmetica, non è necessaria alcuna notazione aggiuntiva, come ad esempio $((...)), per forzare la valutazione aritmetica.


l'ultimo non funziona per me; Sto usando Bash v4.1.2 (1): invece di stampare l'ultimo elemento, stampa l'intero array.
Alexej Magura,

La risposta di @ cuonglm funziona, tuttavia.
Alexej Magura,

La risposta sarebbe ancora migliore se potessi qualificarti moderncon una versione.
Samveen,

1
Esattamente ciò che era necessario per rendere perfetta la risposta.
Samveen,

1
Grazie per questo. Stavo usando echo $ {a [$ (($ {# a [@]} - 1]))} perché non sapevo che "bash tratta gli indici di array come un'espressione aritmetica".
Bruno Bronosky,

15

bashl'assegnazione dell'array, il riferimento, il disinserimento con indice negativo sono stati aggiunti solo in bash 4.3 . Con la versione precedente di bash, è possibile utilizzare l'espressione nell'indicearray[${#array[@]-1}]

Un altro modo, funziona anche con la versione precedente di bash(bash 3.0 o superiore):

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

o:

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

Utilizzando l'offset negativo, è necessario separarsi :con -per evitare di essere confusi con l' :-espansione.


1
Fare che "${a[@]: -1}"e funzionerà (oltre bashe zsh) anche in ksh.
Janis,

I documenti di Kornshell ( www2.research.att.com/sw/download/man/man1/ksh.html ) lo specificano completamente. (Non ho ispezionato i documenti di zsho bash; ma l'ho provato in tutte e tre le conchiglie.)
Janis

@Janis: rileggi la documentazione di Bash, menzionando anche questa. Grazie ancora.
cuonglm,

4

Vettore

Le alternative più vecchie in bash (da bash 3.0+) sono:

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

Lo spazio è necessario per evitare l'interpretazione di :seguito da un segno meno -come espansione di "${var:-abc}"(Usa valori predefiniti).

Il ~è un'aritmetica negazione bit a bit (equivalente a complemento a uno o capovolgere tutti i bit ). Da man bash:

VALUTAZIONE ARITMETICA

      ! ~         logical and bitwise negation  

Da bash-4.2 + anche:

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

Da bash 5.0+ anche:

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

Per tutte le versioni di bash (bash precedente):

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

@

Per argomenti posizionali (dal bash 2.01):

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

Una soluzione portatile per tutte le shell è usare eval:

eval printf '"%s\n"' \"\${$#}\"

Hai un riferimento per la sintassi bash 5+? Ho cercato tutte le 58 istanze di ~nel manuale e non l'ho visto.
Tom Hale,

... e come lo fai $@? bash: ${@[@]:(-1)}: bad substitution
Tom Hale,

1
Sì, c'è un man bashriferimento (controlla la risposta estesa al titolo @). @ TomHale
Isaac,

1
Il @è non un array (bene, non completamente un array ) in bash e non accetta l'indice ( []pedice) per singoli argomenti. Devi usare ${@:(-1)}o equivalente. Controlla la voce estesa nel @titolo. @ TomHale
Isaac,

-2

Inoltre puoi farlo:

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

Risultato:

$ f

Quello che stai facendo è ottenere tutto il conteggio degli elementi nell'array e sottrarre -1 perché stai ottenendo tutti gli elementi, non partendo dall'indice dell'array che è 0.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.