Presentamos los arrays en el capítulo Arrays. Este documento te mostrará más formas de usar los arrays.
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"
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 "$*"
}
(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.
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")
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.
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.
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).
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"
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
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.
$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.