Adicione um novo elemento a uma matriz sem especificar o índice no Bash

Respostas:

1540

Sim existe:

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

Manual de Referência do Bash :

No contexto em que uma instrução de atribuição está atribuindo um valor a uma variável de shell ou índice de matriz (consulte Matrizes), o operador '+ =' pode ser usado para acrescentar ou adicionar ao valor anterior da variável.

Etienne Dechamps
fonte
21
Isso funciona bem com o bash 3.2.48 (OS X 10.8.2). Observe que ARRAYé apenas um espaço reservado para um nome de variável real. Mesmo que seus índices de matriz são não sequencial, acrescentando com +=simplesmente atribuir ao maior índice de + 1.
mklement0
3
Existe algo parecido com isso na versão 4.2.24 (1) do bash?
Ali Ismayilov
195
É importante observar que ARRAY + = ('foo') é muito diferente de ARRAY + = 'foo', que acrescenta a string 'foo' à entrada com a tecla mais baixa (?).
TheConstructor
8
De acordo com wiki.bash-hackers.org/scripting/bashchanges , essa sintaxe apareceu pela primeira vez na versão 3.1-alpha1.
precisa
39
@ Jas: Para acessar toda a matriz, você deve usar ${myarray[@]}- referenciar uma variável da matriz como se ela fosse um escalar é o mesmo que acessar seu elemento 0; em outras palavras: $myarrayé o mesmo que ${myarray[0]}.
mklement0
76

Como Dumb Guy aponta, é importante observar se a matriz começa em zero e é seqüencial. Como você pode fazer atribuições e definir índices ${#array[@]}não contíguos nem sempre é o próximo item no final da matriz.

$ 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

Veja como obter o último índice:

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

Isso ilustra como obter o último elemento de uma matriz. Você verá frequentemente isso:

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

Como você pode ver, porque estamos lidando com uma matriz esparsa, esse não é o último elemento. Isso funciona em matrizes esparsas e contíguas, no entanto:

$ echo ${array[@]: -1}
i
Pausado até novo aviso.
fonte
3
Coisas boas; nunca soube que a sintaxe de extração de extração de substrato também poderia ser aplicada a matrizes; as regras, determinadas por tentativa e erro, são (bash 3.2.48): ${array[@]: start[:count]}Retorna a contagem de elementos. ou, se não especificado, todos os elementos restantes . começando no seguinte elem .: - Se iniciar> = 0: a partir do elem. cujo índice é> = start. - Se começar <0: do elem. cujo índice é (último índice da matriz + 1) - abs (início); CAVEAT: se abs (início)> (último índice da matriz + 1), uma string nula é retornada. Se count for especificado, muitos elementos serão retornados, mesmo que seus índices não sejam contíguos desde o início.
usar o seguinte comando
3
@mklement: No Bash 4.2, você pode usar subscritos negativos da matriz para acessar os elementos contados a partir do final da matriz. ${array[-1]}
Pausado até novo aviso.
É bom saber disso, obrigado. O OS X (a partir do 10.8.2) ainda usa o 3.2.48 e o stackoverflow.com/questions/10418616/… me diz que, infelizmente, "a Apple usa uma versão bastante antiga do Bash, pois não envia o código licenciado sob GPL3 ".
usar o seguinte comando
49
$ declare -a arr
$ arr=("a")
$ arr=("${arr[@]}" "new")
$ echo ${arr[@]}
a new
$ arr=("${arr[@]}" "newest")
$ echo ${arr[@]}
a new newest
ghostdog74
fonte
8
agradável para versões festança que não suportam a semântica do operador + = explicado por e-t172
akostadinov
12
uma boa solução compatível com versões anteriores, mas lembre-se de que, se algum dos elementos existentes tiver espaços, eles serão divididos em vários elementos; usar arr=("${arr[@]}" "new")se você tem elementos com espaços entre eles
kbolino
1
Isso também pode ser usado para empurrar na frente da matriz, que é exatamente o que eu preciso.
Tomáš Zato - Restabelece Monica
29

Se sua matriz é sempre seqüencial e inicia em 0, você pode fazer o seguinte:

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

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

Se você inadvertidamente usar espaços entre o sinal de igual:

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

Você receberá um erro semelhante a:

array_name[3]: command not found
Dumb Guy
fonte
5
Sim, você pode, mas a +=sintaxe (consulte a resposta da @ e-t172) é (a) mais simples e (b) também funciona com matrizes que não são contíguas e / ou não começam com 0.
mklement0
Honestamente, esta solução (para mim) está funcionando melhor do que o "+ =", porque com o último o comprimento às vezes está errado (aumenta em dois ao adicionar um elemento) ... então prefiro esta resposta! :)
Pierpaolo Cira
Isso também funciona nas versões anteriores do bash, antes da +=adição, por exemplo, versão 2
Zoey Hewll 11/11/19
1
Isso também funciona quando seus elementos possuem espaços - $arr += ($el)pareciam dividir a cadeia por espaço e adicionar cada um dos elementos.
Max
5

Com uma matriz indexada, é possível algo como isto:

declare -a a=()
a+=('foo' 'bar')
Grégory Roche
fonte