Introdujimos los arrays en el capítulo Arrays. Este documento mostrará más formas de usar arrays.
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"
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 "$*"
}
(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.
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")
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.
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.
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).
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"
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
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.
$1, $2, etc."$@"
"$*"
$#
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.