Чи є спосіб зчитування останнього елемента масиву з bash?


68

Якщо у мене є масив з 5 елементів, наприклад:

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

Використовуючи, echo ${myarray[4]}я бачу, що він містить.

Але що робити, якщо я не знав кількість елементів у заданому масиві? Чи існує спосіб зчитування останнього елемента масиву невідомої довжини? тобто перший елемент, який читається справа наліво для будь-якого масиву?

Я хотів би знати, як це зробити в баш.


$@не зовсім масив (не можна підписати). Для цього див. Розділ Отримання останнього аргументу, переданого сценарію оболонки .
Том Хейл

Відповіді:


89

Ви можете просто використовувати негативний індекс, ${myarray[-1]} щоб отримати останній елемент. Можна зробити те ж саме для другого-останнього тощо; в Bash:

Якщо індекс, використаний для посилання на елемент індексованого масиву, оцінює число менше нуля, воно інтерпретується як відносне до одного, що перевищує максимальний індекс масиву, тому від'ємні індекси відлічуються від кінця масиву, і індекс -1 відноситься до останнього елемента.

Те ж саме працює і для призначення. Коли він говорить «вираз», це насправді означає вираз; Ви можете написати там будь-який арифметичний вираз для обчислення індексу, включаючи той, який обчислює, ${#myarray[@]}чітко використовуючи довжину масиву .


2
Ви можете це зробити kshі zshв і.
Яніс

5
З zshхоча, за замовчуванням масиви 1 індексовані, в відміну bashта kshде вони знаходяться 0 індексовані.
Стівен Кітт

2
Так, звісно; коротка відповідь на це питання не змінюється, але оскільки згадувалася довга форма, я вважав за потрібне вказати на різницю в поведінці.
Стівен Кітт

22
Негативний індекс працює лише в басі 4.3 і вище.
cuonglm

10
Версія Bash, включена до Mac OS X принаймні v10.11.5, становить лише 3,2, тому це не працює на Mac.
Doktor J

44

Сучасний баш (v4.1 або вище)

Ви можете прочитати останній елемент в індексі -1:

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

Підтримка доступу до числових індексованих масивів з кінця з використанням негативних індексів, розпочатих з версії 4.1 basfa bash .

Старіший bash (v4.0 або новіший)

Ви повинні отримати довжину масиву з, ${#a[@]}а потім відняти один, щоб отримати останній елемент:

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

Оскільки bash трактує абонементи масиву як арифметичний вираз, немає необхідності в додатковій нотації, наприклад $((...)), для примусової арифметичної оцінки.


останній не працює для мене; Я використовую Bash v4.1.2 (1): замість того, щоб друкувати останній елемент, він просто виводить весь масив.
Олексій Магура

@ cuonglm відповідь працює, однак.
Олексій Магура

Відповідь буде ще кращою, якби ви могли претендувати modernна версію.
Самвін

1
Саме те, що було потрібно для того, щоб зробити привид ідеальним.
Самвін

1
Дякую за це. Я використовував echo $ {a [$ (($ {# a [@]} - 1]))}, тому що я не знав про "bash трактує підписки масиву як арифметичний вираз".
Бруно Броноський

15

bashприсвоєння масиву, посилання, зміщення з від'ємним індексом додано лише в басі 4.3 . З більш старшою версією bashви можете використовувати вираження в індексіarray[${#array[@]-1}]

Ще один спосіб - також працювати зі старішою версією bash(bash 3.0 або вище):

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

або:

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

Використовуючи негативний зсув, необхідно відокремити :з , -щоб уникнути плутати з :-розширенням.


1
Зробіть це, "${a[@]: -1}"і воно буде працювати (крім bashі zsh) і в ksh.
Яніс

Документи Kornshell ( www2.research.att.com/sw/download/man/man1/ksh.html ) вказують її повністю. (Я не оглянув документи zshабо bash; але я перевірив їх у всіх трьох оболонках.)
Janis

@Janis: перечитайте документацію bash, вона також згадувала і про цю. Знову дякую.
cuonglm

4

масив

Найдавнішою альтернативою в bash (Since bash 3.0+) є:

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

Пробіл необхідний, щоб уникнути інтерпретації з :наступним мінусом -як розширенням "${var:-abc}"(Використовувати значення за замовчуванням).

Це ~арифметичне побітове заперечення (еквівалентне доповненню чи перегортанню всіх біт ). Від man bash:

АРИТМЕТИЧНА ОЦІНКА

      ! ~         logical and bitwise negation  

Так як bash-4.2 + також:

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

З bash 5.0+ також:

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

Для всіх версій bash (старіших bash):

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

@

Для позиційних аргументів (з bash 2.01):

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

Портативним рішенням для всіх оболонок є використання eval:

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

Чи є у вас посилання на синтаксис bash 5+? Я шукав все 58 примірників ~в керівництві і не бачив його.
Том Хейл

... і як це робити $@? bash: ${@[@]:(-1)}: bad substitution
Том Хейл

1
Так, є man bashпосилання (перевірте розширену відповідь за заголовком @). @TomHale
Ісаак

1
@Це НЕ масив (ну, не повністю масив ) в Баш і не приймає індекс ( []) індекс для окремих аргументів. Вам потрібно використовувати ${@:(-1)}або аналогічний. Перевірте розширений запис у @заголовку. @TomHale
Ісаак

-2

Також ви можете це зробити:

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

Результат:

$ f

Те, що ви робите, - отримувати всі підрахунки елементів у масиві і віднімати -1, оскільки ви отримуєте всі елементи, не починаючи з індексу масиву, який дорівнює 0.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.