Добавить новый элемент в массив без указания индекса в Bash

Ответы:

1541

Да, есть:

ARRAY=()
ARRAY+=('foo')
ARRAY+=('bar')

Справочное руководство Bash :

В контексте, где оператор присваивания присваивает значение переменной оболочки или индексу массива (см. Массивы), оператор «+ =» может использоваться для добавления или добавления к предыдущему значению переменной.

Этьен Дечам
источник
21
Это прекрасно работает с bash 3.2.48 (OS X 10.8.2). Обратите внимание, что ARRAYэто просто заполнитель для фактического имени переменной. Даже если индексы вашего массива не последовательные, добавление с помощью +=просто назначит наибольший индекс +1.
mklement0
3
Есть ли что-то подобное в bash версии 4.2.24 (1)?
Али Исмайлов
195
Важно отметить, что ARRAY + = ('foo') отличается от ARRAY + = 'foo', который добавляет строку 'foo' к записи с самым низким (?) Ключом.
TheConstructor
8
Согласно wiki.bash-hackers.org/scripting/bashchanges , этот синтаксис впервые появился в версии 3.1-alpha1.
Дэвид Йо
39
@Jas: Чтобы получить доступ ко всему массиву, вы должны использовать ${myarray[@]}- ссылка на переменную массива, как если бы это был скаляр, аналогична обращению к его элементу 0; другими словами: так $myarrayже, как ${myarray[0]}.
mklement0
76

Как отмечает Dumb Guy , важно отметить, начинается ли массив с нуля и является ли он последовательным. Поскольку вы можете присваивать и удалять несмежные индексы, ${#array[@]}это не всегда следующий элемент в конце массива.

$ array=(a b c d e f g h)
$ array[42]="i"
$ unset array[2]
$ unset array[3]
$ declare -p array     # dump the array so we can see what it contains
declare -a array='([0]="a" [1]="b" [4]="e" [5]="f" [6]="g" [7]="h" [42]="i")'
$ echo ${#array[@]}
7
$ echo ${array[${#array[@]}]}
h

Вот как получить последний индекс:

$ end=(${!array[@]})   # put all the indices in an array
$ end=${end[@]: -1}    # get the last one
$ echo $end
42

Это показывает, как получить последний элемент массива. Вы часто будете видеть это:

$ echo ${array[${#array[@]} - 1]}
g

Как видите, поскольку мы имеем дело с разреженным массивом, это не последний элемент. Это работает как для разреженных, так и для смежных массивов, хотя:

$ echo ${array[@]: -1}
i
Приостановлено до дальнейшего уведомления.
источник
3
Качественный товар; никогда не знал, что синтаксис извлечения подстрок можно применять и к массивам; правила, определенные методом проб и ошибок (bash 3.2.48): ${array[@]: start[:count]}Возвращает количество элементов. или, если не указано, все остальные элементы. начиная со следующего элемента .: - Если старт> = 0: от элемента. чей индекс> = начало. - Если начало <0: от элемента. чей индекс (последний индекс массива + 1) - abs (начало); CAVEAT: если abs (start)> (последний индекс массива + 1), возвращается пустая строка. Если указано количество, возвращается столько элементов, даже если их индексы не являются смежными с самого начала.
mklement0
3
@mklement: в Bash 4.2 вы можете использовать отрицательные индексы массива для доступа к элементам, считающим с конца массива. ${array[-1]}
Приостановлено до дальнейшего уведомления.
Это приятно знать, спасибо. OS X (по состоянию на 10.8.2) по-прежнему использует 3.2.48, и stackoverflow.com/questions/10418616/… говорит мне, что, к сожалению, «Apple использует довольно старую версию Bash, поскольку они не поставляют лицензионный код под GPL3. "
mklement0
49
$ declare -a arr
$ arr=("a")
$ arr=("${arr[@]}" "new")
$ echo ${arr[@]}
a new
$ arr=("${arr[@]}" "newest")
$ echo ${arr[@]}
a new newest
ghostdog74
источник
8
хорошо для версий bash, которые не поддерживают семантику оператора + =, объясненного e-t172
akostadinov
12
хорошее обратно-совместимое решение, но имейте в виду, что если в любом из существующих элементов есть пробелы, они будут разбиты на несколько элементов; используйте, arr=("${arr[@]}" "new")если у вас есть элементы с пробелами в них
kbolino
1
Это также может быть использовано для толкания перед массивом, а это как раз то, что мне нужно.
Томаш Зато - Восстановить Монику
29

Если ваш массив всегда последовательный и начинается с 0, то вы можете сделать это:

array[${#array[@]}]='foo'

# gets the length of the array
${#array_name[@]}

Если вы случайно используете пробелы между знаком равенства:

array[${#array[@]}] = 'foo'

Тогда вы получите ошибку, похожую на:

array_name[3]: command not found
Тупой парень
источник
5
Да, вы можете, но +=синтаксис (см. Ответ @ e-t172) (а) проще, и (б) также работает с массивами, которые не являются смежными и / или не начинаются с 0.
mklement0
Честно говоря, это решение (для меня) работает лучше, чем "+ =", потому что с последним длина иногда неверна (увеличивается на два при добавлении одного элемента) ... поэтому я предпочитаю этот ответ! :)
Pierpaolo
Это также работает в более ранних версиях bash, до того, как +=был добавлен, например, версия 2
Zoey Hewll
1
Это также работает, когда в ваших элементах есть пробелы - $arr += ($el)казалось, разделить строку на пробел и добавить каждый из элементов.
Макс
5

С индексированным массивом вы можете что-то вроде этого:

declare -a a=()
a+=('foo' 'bar')
Грегори Рош
источник