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

Más sobre los arrays en Bash

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

Acerca de Más sobre los arrays

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

Concatenar los elementos de un array en un solo string

En el capítulo anterior de Arrays, viste "${myarray[@]}", con el índice @, usado para expandir el array en los elementos individuales. Pero a veces quieres unir todos los elementos en un solo string. Para esto, 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, tabulador y nueva 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 diferente:

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 en la función significa que no tenemos que guardar el valor antiguo y restaurarlo a su valor anterior en el scope global.

Como refinamiento, el parámetro especial "$*", cuando se entrecomilla, 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 una 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 una subshell (una copia del shell actual). Cuando los comandos dentro de los paréntesis terminan, la subshell sale, 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 array

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 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 desplazamiento 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 puedas conocer. 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 recopilas 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 realizado en el array dentro de la función no se refleja en el scope exterior.

Pasar el nombre del array

Esta técnica se parece más a la capacidad de «paso por referencia» que puedas conocer de otros lenguajes. Pasas el nombre del array como un string. 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 variables «escalares» (que contienen un valor string).

Note

Dentro de la función, declare -p local_array no es muy útil. Solo mostrará declare -n local_array="array_original". Puedes obtener información detallada sobre el array inspeccionando el nombre del array pasado: declare -p "$1"

Caution

Ten cuidado de que el array local tenga un nombre diferente al array pasado. El código seguirá funcionando, pero emitirá advertencias de «referencia circular de nombre» 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 hacer es usar 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 un solo string 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 nueva ventana o pestaña