Como desabilitar o intervalo do array no Bash

Como desabilitar o intervalo do array no Bash

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

Minha matriz

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

Imprimir matriz 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?

Encontrei outra maneira de excluir o intervalo do array, 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'

Responder1

Uma coisa a ter em mente é que basharrays implementados como ksh, isto é, arrays associativos onde as chaves são limitadas a números inteiros positivos (ao contrário de outras linguagens como perlou zshpor exemplo).

Em:

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

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

Em kshor bash, ${a[@]:0:1}retorna o primeiro elemento do array na lista de elementos ordenados numericamente por chave onde a chave é maior ou igual a 0. Portanto, nesse caso, ele retorna ${a[123]}, não ${a[0]}.

unset 'a[123]'

(lembre-se de citá-lo, caso contrário, falharia se houvesse um arquivo chamado a1 ou a2 ou a3 no diretório atual) faz sentido, pois remove uma chave específica da matriz.

unset 'a[@]::2'

faz menos sentido embora. bashentende apenas unset a, unset 'a[123]'ou unset 'a[*/@]', qualquer coisa depois é ignorada, então unset 'a[@]::2'e unset 'a[@]please'faça o mesmo: desmarque todo o array.

Se você quiser desabilitar um intervalo de chaves, precisará percorrer as chaves:

Para obter a lista de chaves do array, a sintaxe é "${!a[@]}". Infelizmente, aplicar um intervalo a isso não funciona bashnem 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 outras linguagens, não vai querer usar unset. Por exemplo, se o array não for esparso em primeiro lugar e você quiser mantê-lo assim (isto é, mudar todos os elementos por 2 em vez de remover a configuração dos dois primeiros), você pode 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. while unset 'a[16,20]'reduziria a matriz para 15 elementos.

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

(ainda com zsh) mudaria os elementos 17 a 20 em 5 posições, portanto a[12]conteria 17.

Responder2

  1. Se sua matriz forcontínuo/não esparso(todos os elementos do conjunto 0..N-1)

    Você pode remover o segundo elemento da matriz com

    unset 'a[1]'
    

    Para remover o 2º, 3º e 4º 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 arrays esparsos): Você pode remover o segundo elemento do array com

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

    Para remover o 2º, 3º e 4º 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
    

informação relacionada