Arrays en Bash

De castillowiki
Revisión del 14:45 4 mar 2021 de Admin (discusión | contribuciones) (Borrar elementos)
(dif) ← Revisión anterior | Revisión actual (dif) | Revisión siguiente → (dif)
Ir a la navegación Ir a la búsqueda

Las nuevas versiones de Bash soportan matrices unidimensionales. Los elementos de matriz se pueden inicializar con la notación variable[xx].

Alternativamente, un script puede introducir todo el conjunto con una declaración explícita de variables. Para recuperar el contenido de un elemento del array, se usan las llaves y corchetes de la siguiente manera: ${elemento[xx]}.

Ejemplos de uso de arrays:

#!/bin/bash

area[11]=23
area[13]=37
area[51]=UFOs
# No hace falta que sean consecutivos.

echo -n "area[11] = "
echo ${area[11]}    #  Se necesitan {llaves}.

echo -n "area[13] = "
echo ${area[13]}

echo "Contents of area[51] are ${area[51]}."

area[5]=$((${area[11]}+${area[13]}))

area2=( zero one two three four )
# otra manera de inicializar un array
echo ${area2[0]}

area3=([17]=seventeen [24]=twenty-four)
# y otra manera, esta vez, indicando la posición de los elementos
echo ${area3[17]}

echo ${#area3[@]}
# Longitud del array

Un ejemplo práctico y error común puede producirse al querer guardar nombres de ficheros en un array:

$ ficheros=$(ls) # MAL. Se guarda en una variable una lista de ficheros, pero no un array
$ ficheros=($(ls)) # Todavía MAL. Si hay ficheros con espacios en sus nombres dará problemas.

$ files=(*)      # Bien!. El asterisco * permite guardar cada nombre de fichero en una posición del array, aunque tenga espacios.

Una manera de recorrer los elementos de un array:

$ for file in "${myfiles[@]}"; do
>     cp "$file" /backups/
> done
Hay que usar la @ y las " " para tener todos los elementos separados entre sí aunque tengan espacios. Si usamos un asterisco dará problemas si algún elemento tiene espacio.

Simular Arrays multidimensionales

Es posible simular los arrays multidimensionales con bash. Lo que en c o java podríamos así:

matriz[3][5]=34;

En Bash lo ponemos así:

$ matriz[5*$ancho+3]=34

En este caso, $ancho es la anchura que queremos simular en la matriz.

Arrays como parámetros

Si pasamos un array como parámetro, una función puede interpretarlo como una sucesión de parámetros, algo que no entiende o una cadena con espacios, pero no un array:

#!/bin/bash

func()
{
echo $1
echo $@
} 

a=(1 2 3 4) 

func $a # MAL, retorna 1 
func ${a[@]} # MAL, retorna 1
func "${a[@]}" # MAL, retorna 1

Ninguna de las anteriores opciones han servido para pasar correctamente el array. Podríamos usar $@ si sólo enviamos un array, pero si queremos enviar dos o más, nos dará problemas.

#!/bin/bash

func()
{
array=("${!1}")
echo ${array[@]}
} 

a=(1 2 3 4)

func $a # MAL 
func ${a[@]} # MAL
func "${a[@]}" # MAL
func 'a[@]' # Bien

Lo que ha pasado es que le pasamos el nombre del array con la @, entonces el ! expande la variable $1 antes de interpretarla. Es decir, ("${!1}") se convierte en ("${a[@]}") que se interpreta como (1 2 3 4) y se le pasa a la variable nueva array.

Observa porqué pasa esto:

$ baba=booba
$ variable=baba
$ echo ${variable} # baba
$ echo ${!variable} # booba

Se trata de una referencia indirecta.

¿Cual es el problema?

El problema es que a la función se le pasa el nombre de la variable, no su valor. En realidad ¿Qué diferencia hay con eso y con usarla directamente?

array=("${a[@]}")

En cualquier caso hay otro problema. Si el array no está completo, es decir, hay huecos entre los índices, el array resultante quedará condensado y no conservará esta peculiaridad.

Estudiemos este ejemplo:

#!/bin/bash
ar=( a b c )
ar[10]=10
test() {
   local ref=$1[@]
   echo ${!ref}
   local array=("${!ref}")
   echo ${array[10]} # no va 
   echo ${array[3]}
   local f=$1[10]
   echo ${!f}
   eval $f=5
   echo ${!f}
}

test ar
echo ${ar[10]}

Es otra manera de enviarlo de como referencia indirecta. El último echo se usa para mostrar que, realmente, siempre estamos trabajando con el mismo array.



http://stackoverflow.com/questions/1063347/passing-arrays-as-parameters-in-bash

http://stackoverflow.com/questions/8082947/how-to-pass-an-array-to-a-bash-function

Arrays Asociativos

declare -a ARRAY 	#Declara un array indexado. No es necesario declararlo siempre, ya que es la opción por defecto.
declare -A ARRAY 	#Declara un array asociativo. Es la única manera de declararlos.

Veamos este ejemplo sacado de [1]

declare -A sentence

sentence[Begin]='Be liberal in what'
sentence[Middle]='you accept, and conservative'
sentence[End]='in what you send'
sentence['Very end']=...
No confíes en que los elementos estén almacenados en el orden en que se guardaron

Otra manera:

sentence=([End]="in what you send" [Middle]="you accept, and conservative " [Begin]="Be liberal in what " ["Very end"]="...")


Borrar elementos

$ array=(pluto pippo)
$ delete=pluto
$ echo ${array[@]/$delete}
pippo
$ array=( "${array[@]/$delete}" ) #Quotes when working with strings

https://stackoverflow.com/questions/16860877/remove-an-element-from-a-bash-array

$ array=(a b c d)
$ unset array[1]
$ array=( ${array[@]} )