Cómo desarmar el rango de matriz en Bash

Cómo desarmar el rango de matriz en Bash

Estoy intentando eliminar el rango de elementos de la matriz pero falla.

mi matriz

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

Imprimir la matriz 0-1 se ve bien

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

Ahora estoy intentando eliminar solo estos elementos usando:

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

Es eliminar toda la matriz.

¿Qué estoy haciendo mal?

Encontré otra forma de eliminar un rango de matriz, pero ¿por qué lo anterior no funciona?

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

EDITAR También lo intenté pero no tuve suerte.

unset -v 'a[@]::2'

Respuesta1

Una cosa a tener en cuenta es que bashse implementaron matrices como ksh, es decir, matrices asociativas donde las claves se limitan a números enteros positivos (a diferencia de otros lenguajes como perlo, zshpor ejemplo).

En:

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

En bash, tienes una matriz asociativa con 3 elementos, mientras que en perl, tendrías una matriz con 790 elementos (789 con zsh).

En ksho bash, ${a[@]:0:1}devuelve el primer elemento de la matriz en la lista de elementos ordenados numéricamente por clave donde la clave es mayor o igual a 0. Entonces, en ese caso, devuelve ${a[123]}, no ${a[0]}.

unset 'a[123]'

(recuerde citarlo, de lo contrario fallaría si hubiera un archivo llamado a1 o a2 o a3 en el directorio actual) tiene sentido, ya que elimina una clave particular en la matriz.

unset 'a[@]::2'

Aunque tiene menos sentido. bashsolo entiende unset a, unset 'a[123]'o unset 'a[*/@]', cualquier cosa posterior se ignora, así que unset 'a[@]::2'haga unset 'a[@]please'lo mismo: desarme toda la matriz.

Si desea desarmar un rango de claves, deberá recorrer las claves:

Para obtener la lista de claves de la matriz, la sintaxis es "${!a[@]}". Desafortunadamente, aplicar un rango a eso no funciona con bashnor ksh, por lo que necesitarías una matriz temporal:

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

Ahora bien, si desea considerar esas matrices como en otros idiomas, no desea usar unset. Por ejemplo, si la matriz no es escasa en primer lugar y desea mantenerla así (es decir, desplazar todos los elementos en 2 en lugar de desarmar los dos primeros), puede hacer cosas como:

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

Eso es reasignar la matriz con la lista de elementos que desea conservar.

A modo de comparación, con zsh.

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

establecería un valor vacío para los elementos 12 a 16. mientras que unset 'a[16,20]'reduciría la matriz a 15 elementos.

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

(aún con zsh) desplazaría los elementos 17 a 20 en 5 posiciones, por lo que a[12]contendría 17.

Respuesta2

  1. Si tu matriz escontinuo/no escaso(todos los elementos del conjunto 0..N-1)

    Puede eliminar el segundo elemento de la matriz con

    unset 'a[1]'
    

    Para eliminar el segundo, tercer y cuarto elemento, puede utilizar, por ejemplo

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

    Para eliminar todos los elementos menos el primero y el segundo, puede usar, por ejemplo

    for ((i=2; i<${#a[@]}; i++)); do unset "a[$i]"; done
    
  2. solución general(funciona también para matrices dispersas): puede eliminar el segundo elemento de la matriz con

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

    Para eliminar el segundo, tercer y cuarto elemento, puede utilizar, por ejemplo

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

    Para eliminar todos los elementos menos el primero y el segundo, puede usar, por ejemplo

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

información relacionada