Como desarmar o intervalo de array no Bash

5

Estou tentando excluir o intervalo do elemento da matriz, mas ele falha.

Meu array

root@ubuntu:~/work# echo ${a[@]}
cocacola.com airtel.com pepsi.com

A matriz Print 0-1 parece ok

root@ubuntu:~/work# echo ${a[@]::2}
cocacola.com airtel.com

Agora estou tentando excluir apenas esses elementos usando:

root@ubuntu:~/work# unset a[@]::2
root@ubuntu:~/work# echo ${a[@]}

É excluir toda a matriz ..

O que estou fazendo de errado?

Eu encontrei outra maneira de excluir o intervalo de matriz, mas por que as coisas acima não estão funcionando?

for ((i=0; i<2; i++)); do unset a[$i]; done

EDIT Eu também tentei, mas sem sorte

unset -v 'a[@]::2'
    
por Rahul Patil 30.04.2013 / 18:02

2 respostas

10

Uma coisa a ter em mente é que bash implementou matrizes como ksh , ou seja, matrizes associativas onde as chaves são limitadas a inteiros positivos (ao contrário de outras linguagens como perl ou zsh por exemplo).

Em:

a[123]=foo a[456]=bar a[789]=baz

No bash, você tem um array associativo com 3 elementos, enquanto que em perl , você teria um array com 790 elementos (789 com zsh).

Em ksh ou bash , ${a[@]:0} retorna o primeiro elemento da matriz na lista de elementos classificados por índices. Então, nesse caso, ele retorna ${a[123]} , não ${a[0]} .

unset 'a[123]'

(lembre-se de citar, senão ele falharia se houvesse um arquivo chamado a1 ou a2 ou a3 no diretório atual) faz sentido, já que remove uma chave particular na matriz.

unset 'a[@]::2'

faz menos sentido embora. bash apenas entende unset a , unset 'a[123]' ou unset 'a[*/@]' , qualquer coisa depois é ignorada, então unset 'a[@]::2' e unset 'a[@]please' fazem o mesmo: anule o array inteiro.

Se você deseja remover um intervalo de chaves, é necessário percorrer as teclas:

Para obter a lista de chaves da matriz, a sintaxe é "${!a[@]}" . Infelizmente, aplicar um intervalo a isso não funciona com bash nem ksh , então você precisaria de um array temporário:

keys=("${!a[@]}")
for i in "${keys[@]::2}"; do unset "a[$i]"; done

Agora, se você quiser considerar esses arrays como em outros idiomas, não deseja usar unset . Por exemplo, se a matriz não for escassa e você quiser mantê-la assim (ou seja, deslocar todos os elementos por 2 em vez de desativar os dois primeiros), é possível fazer coisas como:

a=("${a[@]:2}")

Isso é reatribuir o array com a lista de elementos que você deseja manter.

Para comparação, com zsh .

a=({1..20})
unset 'a[12,16]'

definiria um valor vazio para os elementos 12 a 16. Enquanto unset 'a[16,20]' reduziria o array para 15 elementos.

a=({1..20})
a[12,16]=()

(ainda com zsh ) mudaria os elementos 17 a 20 por 5 posições, então a[12] conteria 17 .

    
por 30.04.2013 / 19:04
1
  1. Se sua matriz for contínua / não esparsa (todos os elementos do conjunto 0..N-1)

    Você pode remover o segundo elemento da matriz com

    unset 'a[1]'
    

    Para remover o segundo, terceiro e quarto elemento, você pode usar, por exemplo,

    for ((i=1; i<=3; i++)); do unset "a[$i]"; done
    

    Para excluir todos, exceto o primeiro e o segundo elemento, você pode usar, por exemplo,

    for ((i=2; i<${#a[@]}; i++)); do unset "a[$i]"; done
    
  2. Solução geral (funciona também para matrizes esparsas): Você pode remover o segundo elemento da matriz com

    unset "a[$(echo ${!a[@]} | cut -d" " -f 2)]"
    

    Para remover o segundo, terceiro e quarto elemento, você pode usar, por exemplo,

    for $(echo ${!a[@]} | cut -d" " -f 2-4) ; do unset "a[$i]"; done
    

    Para excluir todos, exceto o primeiro e o segundo elemento, você pode usar, por exemplo,

    for $(echo ${!a[@]} | cut -d" " -f 2-) ; do unset "a[$i]"; done
    
por 30.04.2013 / 18:20

Tags