Apresentamos os arrays no capítulo Arrays. Este documento mostra outras formas de usar arrays.
No capítulo anterior sobre arrays, você viu "${myarray[@]}", com o índice @, usado para expandir o array nos elementos individuais.
Mas às vezes você quer juntar todos os elementos em uma única string.
Para isso, use o índice *:
echo "${myarray[*]}"
É obrigatório envolver a expansão em aspas duplas.
O Bash usa o primeiro caractere da variável embutida IFS como caractere separador.
Por padrão, $IFS é composto de espaço, tabulação e quebra de linha.
myarray=(one two three four)
mystring="${myarray[*]}"
declare -p mystring
# => declare -- mystring="one two three four"
Podemos manipular a variável IFS para usar um caractere 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 o IFS dentro da função significa que não precisamos salvar o valor antigo e restaurá-lo ao valor anterior no escopo global.
Como refinamento, o parâmetro especial "$*", quando está entre aspas, tem a mesma funcionalidade, então não precisamos salvar uma cópia dos argumentos da função:
join() {
local IFS=$1
shift
echo "$*"
}
(IFS=","; echo "${myarray[*]}")
Os parênteses criam um subshell (uma cópia do shell atual). Quando os comandos dentro dos parênteses terminam, o subshell encerra e a variável IFS alterada desaparece.
Observe que isso não vai funcionar: IFS="," echo "${myarray[*]}" -- a expansão de parâmetro é realizada primeiro, antes de o shell aplicar a variável IFS modificada ao comando echo.
Talvez você já tenha visto a expansão de parâmetro "${variable:offset:length}", que expande para uma substring do valor da variável.
Podemos fazer a mesma coisa com arrays para expandir uma fatia do 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 a parte do comprimento significa "do offset até o fim do array":
subarray=("${myarray[@]:2}")
declare -p subarray
# => declare -a subarray=([0]="three" [1]="four")
Isso não é tão simples quanto em outras linguagens que você talvez conheça. Existem duas técnicas principais para passar um array para uma função.
Na primeira técnica, você passa todos os valores do array e os recolhe em um array local dentro da função.
myfunc() {
local array_copy=("$@")
# do stuff with array_copy
declare -p array_copy
}
array_original=(11 22 33 44)
myfunc "${array_original[@]}"
O array da função contém uma cópia dos valores. Quaisquer alterações feitas no array dentro da função não se refletem no escopo externo.
Essa técnica se parece mais com o recurso de "passagem por referência" que você talvez conheça de outras linguagens. Você passa o nome do array como uma string. A função cria uma variável local com o atributo "nameref". Esse array local e o array global (cujo nome passamos) são o mesmo 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")
Namerefs também funcionam com arrays associativos e com variáveis "escalares" (que contêm um valor de string).
Dentro da função, declare -p local_array não é muito útil.
Ele apenas emite declare -n local_array="array_original".
Você pode obter informações detalhadas sobre o array inspecionando o nome do array passado: declare -p "$1"
Tome cuidado para que o array local tenha um nome diferente do array passado. O código ainda vai funcionar, mas emite avisos de "circular name reference" como este:
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
Em shells que buscam seguir apenas o padrão POSIX (como ash e dash), não existem arrays.
O mais próximo que você consegue chegar é usar os parâmetros posicionais.
$1, $2, etc."$@"
"$*"
$#
Use o comando set para atribuir valores a eles:
set -- one two three
set -- "$@" four
for item in "$@"; do
echo "do something with $item"
done
Se o seu objetivo é escrever scripts de shell "portáveis", você vai usar os parâmetros posicionais para armazenar uma "lista" de valores.