Arrays no Bash

1. Introdução aos Arrays no Bash

Arrays no Bash são estruturas de dados que permitem armazenar múltiplos valores em uma única variável. Eles são fundamentais para scripts mais complexos, pois evitam a criação de dezenas de variáveis separadas e permitem operações em lote com facilidade.

Existem dois tipos principais de arrays no Bash:

  • Arrays indexados (numéricos): Os elementos são acessados por índices numéricos, começando em 0.
  • Arrays associativos (mapas): Os elementos são acessados por chaves nomeadas (strings). Disponível a partir do Bash 4.

Arrays podem ser declarados explicitamente com declare ou implicitamente ao atribuir valores entre parênteses.

# Declaração explícita
declare -a meu_array

# Declaração implícita (inicialização direta)
meu_array=("valor1" "valor2" "valor3")

2. Declaração e Inicialização de Arrays

A sintaxe básica para criar um array indexado é usar parênteses com elementos separados por espaços:

frutas=("maçã" "banana" "laranja" "uva")

É possível inicializar com índices específicos:

dias[0]="segunda"
dias[3]="quinta"

Arrays vazios também são úteis para serem preenchidos dinamicamente:

vazio=()

Elementos com espaços devem estar entre aspas para evitar quebra indesejada:

usuarios=("João Silva" "Maria Souza" "Carlos Pereira")

3. Acessando Elementos e Índices

Para acessar um elemento individual, use ${array[índice]}:

echo "${frutas[0]}"   # maçã
echo "${frutas[2]}"   # laranja

Para listar todos os elementos, use ${array[@]} (cada elemento como palavra separada) ou ${array[*]} (todos em uma string):

echo "${frutas[@]}"   # maçã banana laranja uva
echo "${frutas[*]}"   # maçã banana laranja uva

Para obter o comprimento do array (número de elementos):

echo "${#frutas[@]}"  # 4

Para listar todos os índices disponíveis:

echo "${!frutas[@]}"  # 0 1 2 3

4. Adicionando, Removendo e Modificando Elementos

Para adicionar elementos ao final do array:

frutas+=("manga" "abacaxi")
echo "${frutas[@]}"   # maçã banana laranja uva manga abacaxi

Para remover um elemento específico, use unset:

unset frutas[1]       # remove "banana"
echo "${frutas[@]}"   # maçã laranja uva manga abacaxi

Atenção: Após unset, os índices não são reordenados automaticamente. O índice 1 fica vazio, mas o array mantém os demais índices. Para reconstruir o array sem buracos:

frutas=("${frutas[@]}")

Para substituir um elemento em posição específica:

frutas[0]="pera"
echo "${frutas[@]}"   # pera laranja uva manga abacaxi

5. Iteração sobre Arrays

A forma mais comum de percorrer elementos é com for:

for fruta in "${frutas[@]}"; do
    echo "Fruta: $fruta"
done

Para percorrer os índices (útil para arrays esparsos):

for indice in "${!frutas[@]}"; do
    echo "Índice $indice: ${frutas[$indice]}"
done

Também é possível usar while com contador:

contador=0
while [ $contador -lt ${#frutas[@]} ]; do
    echo "${frutas[$contador]}"
    ((contador++))
done

6. Arrays Associativos (Bash 4+)

Arrays associativos exigem declaração explícita com declare -A:

declare -A capitais
capitais["Brasil"]="Brasília"
capitais["Argentina"]="Buenos Aires"
capitais["Chile"]="Santiago"

Acesso e iteração:

echo "${capitais["Brasil"]}"   # Brasília

for pais in "${!capitais[@]}"; do
    echo "Capital do $pais: ${capitais[$pais]}"
done

Diferenças práticas entre arrays indexados e associativos:

Característica Indexado Associativo
Índice Número inteiro String
Declaração declare -a ou implícita declare -A obrigatório
Ordem Mantida por inserção Não garantida
Uso típico Listas sequenciais Mapas chave-valor

7. Operações Avançadas e Boas Práticas

Copiando arrays:

novo_array=("${frutas[@]}")

Fatiamento (slicing):

# ${array[@]:inicio:quantidade}
slice=("${frutas[@]:1:2}")
echo "${slice[@]}"   # laranja uva

Cuidados com espaços e caracteres especiais:

Sempre use aspas duplas ao expandir arrays para preservar elementos com espaços:

# ERRADO - quebra elementos com espaços
for usuario in ${usuarios[@]}; do
    echo "$usuario"
done

# CORRETO
for usuario in "${usuarios[@]}"; do
    echo "$usuario"
done

Evitando armadilhas comuns:

  • Globbing: Ao usar ${array[*]} sem aspas, padrões como * podem ser expandidos pelo shell.
  • Split com IFS: Modificar IFS pode alterar como ${array[*]} separa elementos.
  • Índices esparsos: Após unset, índices não são reordenados. Use array=("${array[@]}") para reindexar.

Exemplo completo com boas práticas:

#!/bin/bash

# Declaração segura
declare -a arquivos

# Populando com find (cuidado com espaços)
while IFS= read -r -d '' arquivo; do
    arquivos+=("$arquivo")
done < <(find /tmp -type f -name "*.txt" -print0)

# Iteração segura
for arquivo in "${arquivos[@]}"; do
    echo "Processando: $arquivo"
done

# Verificando comprimento
echo "Total de arquivos: ${#arquivos[@]}"

Referências