Arrays associativos são uma estrutura de dados poderosa em Bash que permitem armazenar pares de chave-valor, onde cada chave é única e pode ser uma string. Diferentemente dos arrays indexados numericamente, os arrays associativos oferecem flexibilidade para acessar dados por nomes significativos, facilitando a organização e a busca de informações. Nesta aula, exploraremos como declarar, manipular e iterar sobre arrays associativos, além de ver casos de uso comuns.

Os arrays associativos foram introduzidos no Bash versão 4.0, portanto certifique-se de estar usando uma versão compatível. Eles são particularmente úteis para tarefas como contagem de frequências, configurações de aplicações e mapeamento de dados.

declare -A

Para usar um array associativo, é necessário declará-lo explicitamente com a opção -A do comando declare. Isso informa ao Bash que a variável será um array associativo. Sem essa declaração, o Bash tratará a variável como um array indexado comum ou como uma variável escalar.

A sintaxe básica é: declare -A nome_do_array. Após a declaração, você pode atribuir valores usando a sintaxe nome_do_array[chave]=valor ou inicializar o array com uma lista de pares chave-valor entre parênteses.

#!/bin/bash
# Declarando um array associativo
declare -A meu_array

# Atribuindo valores
meu_array["nome"]="Alice"
meu_array["idade"]=30
meu_array["cidade"]="São Paulo"

# Acessando valores
echo ${meu_array["nome"]}  # Saída: Alice
echo ${meu_array["idade"]} # Saída: 30

Também é possível declarar e inicializar o array em uma única linha, usando a sintaxe de lista entre parênteses com pares chave-valor separados por espaços. Cada par é definido como [chave]=valor.

declare -A cores=(
    ["vermelho"]="#FF0000"
    ["verde"]="#00FF00"
    ["azul"]="#0000FF"
)

echo ${cores["vermelho"]}  # Saída: #FF0000

Chave-valor

As operações básicas com arrays associativos envolvem adicionar, acessar, modificar e remover pares chave-valor. As chaves são sempre strings, e os valores podem ser qualquer string ou número. É importante notar que as chaves são sensíveis a maiúsculas/minúsculas.

Para acessar um valor, use a sintaxe ${array[chave]}. Para modificar um valor existente, basta reatribuir. Para remover um par, use unset array[chave]. Para listar todas as chaves ou todos os valores, use ${!array[@]} e ${array[@]}, respectivamente.

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

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

# Modificar
capitals["Brasil"]="Brasília (DF)"

# Remover
unset capitals["Argentina"]

# Listar chaves
echo ${!capitals[@]}  # Brasil Chile (ordem não garantida)

# Listar valores
echo ${capitals[@]}    # Brasília (DF) Santiago

Uma operação comum é verificar se uma chave existe no array. Isso pode ser feito com uma expansão condicional ou com o operador -v do Bash 4.2+.

if [[ -v capitals["Brasil"] ]]; then
    echo "Existe"
else
    echo "Não existe"
fi

Iteração

Iterar sobre arrays associativos é essencial para processar todos os pares. Você pode percorrer as chaves usando for chave in "${!array[@]}" e, dentro do loop, acessar o valor correspondente com ${array[$chave]}.

declare -A precos
precos["maçã"]=2.50
precos["banana"]=1.80
precos["laranja"]=3.00

for fruta in "${!precos[@]}"; do
    echo "$fruta custa R$ ${precos[$fruta]}"
done

Outra forma é percorrer diretamente os valores, se você não precisar das chaves: for valor in "${array[@]}". No entanto, lembre-se que a ordem de iteração não é garantida e pode variar entre versões do Bash.

Para obter o número de elementos, use ${#array[@]}.

echo "Total de frutas: ${#precos[@]}"

Casos de uso

Arrays associativos são úteis em diversas situações. Um exemplo clássico é contar a frequência de palavras em um texto. Outro é armazenar configurações de um programa, onde as chaves são nomes de parâmetros. Também podem ser usados para criar um mapa de dados relacionais.

Exemplo: Contagem de palavras em uma frase.

#!/bin/bash
frase="o rato roeu a roupa do rei de roma"
declare -A contagem
for palavra in $frase; do
    ((contagem["$palavra"]++))
done

for palavra in "${!contagem[@]}"; do
    echo "$palavra: ${contagem[$palavra]}"
done

Outro caso: mapear nomes de arquivos para seus tamanhos.

declare -A tamanhos
for arquivo in /var/log/*.log; do
    nome=$(basename "$arquivo")
    tamanhos["$nome"]=$(stat -c%s "$arquivo")
done

for nome in "${!tamanhos[@]}"; do
    echo "$nome: ${tamanhos[$nome]} bytes"
done

Boas práticas e observações finais

Sempre declare arrays associativos com declare -A antes de usá-los para evitar comportamentos inesperados. Lembre-se de que as chaves são strings, então use aspas ao redor de chaves que contenham espaços ou caracteres especiais. Ao iterar, coloque as aspas duplas em torno das expansões para preservar palavras com espaços. Arrays associativos não são ordenados; se precisar de ordem, considere usar um array indexado separado para as chaves.

Referências

Exercícios

  1. Crie um script que declare um array associativo com nomes de alunos e suas notas. Adicione pelo menos 3 alunos e imprima a nota de um deles.

    ✓ Resposta:
    #!/bin/bash
    declare -A notas
    notas["João"]=8.5
    notas["Maria"]=9.0
    notas["Pedro"]=7.0
    echo ${notas["Maria"]}
  2. Escreva um script que itere sobre um array associativo de países e suas capitais, imprimindo cada par no formato "País: Capital".

    ✓ Resposta:
    #!/bin/bash
    declare -A capitals
    capitals["Brasil"]="Brasília"
    capitals["Argentina"]="Buenos Aires"
    capitals["Chile"]="Santiago"
    
    for pais in "${!capitals[@]}"; do
        echo "$pais: ${capitals[$pais]}"
    done
  3. Crie um script que leia uma string de palavras separadas por espaço e use um array associativo para contar quantas vezes cada palavra aparece. Imprima cada palavra e sua contagem.

    ✓ Resposta:
    #!/bin/bash
    frase="shell script é legal e shell script é poderoso"
    declare -A contagem
    for palavra in $frase; do
        ((contagem["$palavra"]++))
    done
    
    for palavra in "${!contagem[@]}"; do
        echo "$palavra: ${contagem[$palavra]}"
    done
  4. Escreva um script que remova uma chave específica de um array associativo e verifique se a remoção foi bem-sucedida.

    ✓ Resposta:
    #!/bin/bash
    declare -A frutas
    frutas["maçã"]=5
    frutas["banana"]=3
    frutas["laranja"]=2
    
    unset frutas["banana"]
    
    if [[ -v frutas["banana"] ]]; then
        echo "banana ainda existe"
    else
        echo "banana removida"
    fi
  5. Crie um script que use um array associativo para armazenar configurações (ex.: usuário, diretório, modo) e depois imprima todas as chaves e valores.

    ✓ Resposta:
    #!/bin/bash
    declare -A config
    config["usuario"]="admin"
    config["diretorio"]="/var/www"
    config["modo"]="755"
    
    for chave in "${!config[@]}"; do
        echo "$chave = ${config[$chave]}"
    done