Tracks
/
Bash
Bash
/
Temario
/
Más sobre arrays
Má

Más sobre arrays en Bash

{one: "1 ejercicio", many: "%{count} de ejercicios", other: "%{count} ejercicios"}

Acerca de Más sobre arrays

Presentamos los arrays en el capítulo Arrays. Este documento te mostrará más formas de usar los arrays.

Concatenar los elementos de un array en una sola cadena

En el capítulo anterior sobre arrays viste "${myarray[@]}", con el índice @, usado para expandir el array en sus elementos individuales. Pero a veces quieres unir todos los elementos en una sola cadena. Para eso, usa el índice *:

echo "${myarray[*]}"

Debes encerrar la expansión entre comillas dobles.

Bash usa el primer carácter de la variable incorporada IFS como carácter separador. Por defecto, $IFS consta de espacio, tabulación y salto de línea.

myarray=(one two three four)
mystring="${myarray[*]}"
declare -p mystring
# => declare -- mystring="one two three four"

Podemos manipular la variable IFS para usar un carácter separador distinto:

myarray=(one two three four)
IFS=","
mystring="${myarray[*]}"
declare -p mystring
# => declare -- mystring="one,two,three,four"
Advanced
Podemos encapsular esto en una función. Haz clic para ver los detalles.
join() {
    local IFS=$1
    shift
    local elements=("$@")
    echo "${elements[*]}"
}

join ":" "${myarray[@]}"     # note, the "@" index
# => "one:two:three:four"

Localizar IFS dentro de la función significa que no tenemos que guardar el valor anterior y restaurarlo a su valor previo en el ámbito global.

Como refinamiento, el parámetro especial "$*", cuando está entre comillas, tiene la misma funcionalidad, así que no necesitamos guardar una copia de los argumentos de la función:

join() {
    local IFS=$1
    shift
    echo "$*"
}
Sin usar una función, modificar IFS en un subshell es una buena forma de evitar modificarlo en el shell actual. Haz clic para ver los detalles.
(IFS=","; echo "${myarray[*]}")

Los paréntesis crean un subshell (una copia del shell actual). Cuando los comandos dentro de los paréntesis terminan, el subshell termina y la variable IFS modificada desaparece.

Ten en cuenta que esto no funcionará: IFS="," echo "${myarray[*]}". La expansión de parámetros se realiza primero, antes de que el shell aplique la variable IFS modificada al comando echo.

Segmentos de arrays

Es posible que hayas visto la expansión de parámetros "${variable:offset:length}", que se expande a una subcadena del valor de la variable. Podemos hacer lo mismo con los arrays para expandir un segmento del array.

myarray=(one two three four)

subarray=("${myarray[@]:0:2}")
declare -p subarray
# => declare -a subarray=([0]="one" [1]="two")

subarray=("${myarray[@]:1:3}")
declare -p subarray
# => declare -a subarray=([0]="two" [1]="three" [2]="four")

Omitir la parte de la longitud significa "desde el offset hasta el final del array":

subarray=("${myarray[@]:2}")
declare -p subarray
# => declare -a subarray=([0]="three" [1]="four")

Pasar un array a una función

Esto no es tan sencillo como en otros lenguajes que quizá conozcas. Hay dos técnicas principales para pasar un array a una función.

Pasar los elementos

En la primera técnica, pasas todos los valores del array y los reúnes en un array local dentro de la función.

myfunc() {
    local array_copy=("$@")
    # do stuff with array_copy
    declare -p array_copy
}

array_original=(11 22 33 44)
myfunc "${array_original[@]}"

El array de la función contiene una copia de los valores. Cualquier cambio que se haga al array dentro de la función no se refleja en el ámbito externo.

Pasar el nombre del array

Esta técnica se parece más a la capacidad de «paso por referencia» que quizá conozcas de otros lenguajes. Pasas el nombre del array como una cadena. La función creará una variable local con el atributo «nameref». Este array local y el array global (cuyo nombre pasamos) son el mismo array.

myfunc() {
    # note the `-n` option
    local -n local_array=$1

    # do stuff with local_array
    for i in "${!local_array[@]}"; do
        printf '%d => %s\n' "$i" "${local_array[i]}"
    end

    # we can mutate it
    local_array+=(55 66 77)
}

array_original=(11 22 33 44)
myfunc "array_original"

# show the mutated array
declare -p array_original
# => declare -a array_original=([0]="11" [1]="22" [2]="33" [3]="44" [4]="55" [5]="66" [6]="77")

Los namerefs también funcionan con arrays asociativos y con variables «escalares» (las que contienen un valor de cadena).

Note

Dentro de la función, declare -p local_array no es de gran ayuda. Solo emite declare -n local_array="array_original". Puedes obtener la información detallada del array inspeccionando el nombre del array que pasaste: declare -p "$1"

Caution

Procura que el array local tenga un nombre distinto al del array que pasaste. El código seguirá funcionando, pero emitirá advertencias de «circular name reference» como esta:

myfunc() {
    local -n a=$1
    local IFS=,
    echo "${a[*]}"
}

# same name as the function's local variable
a=(one two three)
myfunc a
bash: local: warning: a: circular name reference
bash: warning: a: circular name reference
bash: warning: a: circular name reference
bash: warning: a: circular name reference
one,two,three

Los parámetros posicionales son «similares a un array»

En los shells que solo pretenden cumplir con el estándar POSIX (como ash y dash), no hay arrays. Lo más parecido que puedes usar son los parámetros posicionales.

  • Se accede a los parámetros posicionales por índice: $1, $2, etc.
  • Se expanden en elementos individuales con "$@"
  • Se concatenan en una sola cadena con "$*"
  • El número de parámetros es $#

Usa el comando set para asignarles valores:

set -- one two three
set -- "$@" four

for item in "$@"; do
    echo "do something with $item"
done

Si tu objetivo es escribir scripts de shell «portables», usarás los parámetros posicionales para almacenar una «lista» de valores.

Editar en GitHub El enlace se abre en una ventana o pestaña nueva