Arrays no Bash: Arrays Indexados e Associativos
O Que Você Vai Aprender
- A diferença entre arrays indexados e arrays associativos no bash
- As operações fundamentais: declarar, acessar, iterar e adicionar/remover elementos
- Como evitar armadilhas clássicas como aspas faltantes em
"${arr[@]}"e arrays esparsos
Resumo Rápido
- Lista ordenada de valores -> array indexado (
arr=(a b c)) - Tabela de busca chave/valor -> array associativo (
declare -A mapé obrigatório) - Sempre use aspas duplas em
"${arr[@]}"ao iterar ou expandir
Pré-requisitos (ambiente alvo)
- Shell: bash 4.0+ (arrays associativos precisam de 4.0+, índices negativos precisam de 4.3+)
sh/dashnão suportam arrays. Use um shebang explícito#!/bin/bash
O que é um array?
Conclusão: Um array armazena múltiplos valores em uma única variável. O bash tem dois tipos: arrays indexados ordenados e arrays associativos baseados em chaves.
Uma variável de shell simples armazena um único valor. Quando você precisa lidar com vários nomes de arquivos ou usuários juntos, colocar tudo em uma string separada por espaços quebra assim que um valor contiver um espaço. Um array mantém cada elemento como um valor independente e seguramente entre aspas.
O bash oferece dois tipos de array:
- Array indexado: elementos são acessados por índices inteiros começando em
0 - Array associativo: elementos são buscados por uma chave de string arbitrária (como um hash ou dicionário)
Como usar arrays indexados?
Conclusão: Declare com
arr=(a b c), leia um elemento com${arr[0]}e todos os elementos com"${arr[@]}". Omitir o índice refere-se ao primeiro elemento.
Declarando e atribuindo
# Declarar tudo de uma vez fruits=(apple banana cherry) # Atribuir por indice fruits[3]=durian # Adicionar ao final (operador +=) fruits+=(elderberry fig)
Acessando
echo "${fruits[0]}" # apple (primeiro elemento)
echo "${fruits[-1]}" # fig (ultimo, bash 4.3+)
echo "${fruits[@]}" # todos os elementos, separados por espaco
echo "${#fruits[@]}" # quantidade de elementos (6)
echo "${!fruits[@]}" # todos os indices (0 1 2 3 4 5)Referenciar um array sem índice, como $fruits, é o mesmo que ${fruits[0]} (apenas o primeiro elemento). Cuidado com essa confusão quando você pretendia usar todos os elementos.
Fatiamento (extraindo um subconjunto)
echo "${fruits[@]:1:2}" # banana cherry (2 elementos a partir do indice 1)Como usar arrays associativos?
Conclusão: Sempre declare um array associativo com
declare -Aantes de usar. Pule isso e o bash o trata como array indexado, colapsando chaves para 0 e corrompendo os dados.
Um array associativo permite usar strings arbitrárias como chaves. A diferença principal dos arrays indexados é que você deve declará-lo com declare -A primeiro.
declare -A capital # esquecer isso e ele quebra
capital[japan]=Tokyo
capital[france]=Paris
capital["united states"]=Washington
echo "${capital[japan]}" # Tokyo
echo "${!capital[@]}" # todas as chaves (ordem indefinida)
echo "${capital[@]}" # todos os valores (ordem indefinida)
echo "${#capital[@]}" # quantidade de elementos (3)Sem declare -A, escrever capital[japan]=Tokyo faz o bash avaliar japan aritmeticamente como 0 e atribuir ao índice 0 de um array indexado. Arrays associativos exigem a declaração.
Arrays associativos não preservam ordem. Nem a ordem de inserção nem a ordem das chaves é garantida na saída, então use pipe com sort se precisar de ordenação.
Como iterar sobre um array?
Conclusão: Itere valores com
for x in "${arr[@]}"e chaves/índices comfor k in "${!arr[@]}". Ambos exigem aspas duplas.
# Processar cada valor por vez
for f in "${fruits[@]}"; do
echo "fruta: $f"
done
# Iterar chaves (associativo) e buscar valores
for country in "${!capital[@]}"; do
echo "$country -> ${capital[$country]}"
doneRemover as aspas, como em for f in ${fruits[@]}, causa divisão de palavras em elementos que contêm espaços: um único elemento apple pie se divide em apple e pie. Sempre use "${arr[@]}" para manter os valores intactos.
Qual é a diferença entre "${arr[@]}" e "${arr[*]}"?
Conclusão:
[@]expande cada elemento como uma palavra separada;[*]junta todos em uma única string usando o primeiro caractere de IFS. Use[@]para loops.
| Notação | Expande para | Uso típico |
|---|---|---|
"${arr[@]}" |
uma palavra separada por elemento | loops, passagem de args |
"${arr[*]}" |
uma única string unida por IFS[0] | exibição, stringify |
arr=(one two three)
printf '[%s]\n' "${arr[@]}" # [one] [two] [three] em linhas separadas
printf '[%s]\n' "${arr[*]}" # [one two three] em uma linha
# Unir com um separador personalizado
IFS=,
echo "${arr[*]}" # one,two,three
unset IFSComo adicionar ou remover elementos?
Conclusão: Adicione com
arr+=(...)e exclua comunset 'arr[2]'. Note que remover de um array indexado o deixa esparso - os índices não são renumerados.
arr=(a b c d)
arr+=(e) # adicionar -> a b c d e
unset 'arr[1]' # excluir indice 1 (b)
echo "${arr[@]}" # a c d e
echo "${!arr[@]}" # 0 2 3 4 <- indice 1 esta faltando (nao renumerado)Após unset, o array não é mais contíguo (array esparso). A contagem ${#arr[@]} não corresponde mais ao maior índice, então qualquer loop assumindo índices 0..N-1 quebra. Reatribua para renumerar:
arr=("${arr[@]}") # reindexar para 0,1,2...Quais são as armadilhas comuns?
Conclusão: Arrays são exclusivos do bash, aspas são obrigatórias, e arrays associativos precisam de declare -A. Perca qualquer um desses e você terá uma falha clássica.
Não faça isso / fácil de errar
- Usar arrays com
#!/bin/sh-> erro de sintaxe nodashetc. Use#!/bin/bash for x in ${arr[@]}(sem aspas) -> elementos com espaços são divididos- Esquecer
declare -Apara um array associativo -> chaves colapsam para 0 e sobrescrevem umas às outras - Escrever
$arrno lugar dearr[0]-> você obtém apenas o primeiro elemento, não todos
Para capturar saída de comandos em um array, mapfile (também chamado readarray) lê com segurança linha por linha.
mapfile -t lines < <(ls -1) # cada linha se torna um elemento de lines
echo "${#lines[@]}" # numero de linhasA opção -t remove a nova linha final de cada linha; sem ela, os elementos mantêm um \n.