Variáveis no Bash: declaração e expansão

1. Introdução às variáveis no Bash

No Bash, variáveis são espaços na memória que armazenam dados — desde números e textos até caminhos de arquivos e resultados de comandos. Diferentemente de linguagens compiladas, no shell tudo é tratado como string até que se prove o contrário.

Existem dois tipos principais: variáveis de ambiente (disponíveis para processos filhos) e variáveis locais (restritas ao shell atual). As variáveis de ambiente são herdadas por subprocessos, enquanto as locais desaparecem ao final do script ou sessão.

Quanto à nomenclatura:
- Nomes podem conter letras, números e underscores (_)
- Não podem começar com número
- Convenção: variáveis de ambiente em MAIÚSCULAS (PATH, HOME), variáveis locais em minúsculas (contador, nome_arquivo)
- Evite nomes reservados como if, then, else, for

# Válidos
nome="João"
contador=10
_PATH="/tmp"

# Inválidos
1nome="erro"      # começa com número
meu-nome="erro"   # hífen não permitido

2. Declaração e atribuição de variáveis

A sintaxe básica é simples: nome=valor. Não pode haver espaços ao redor do = — essa é uma das fontes mais comuns de erro para iniciantes.

# Atribuição básica
nome="Maria"
idade=30

Para valores com espaços ou caracteres especiais, use aspas:

# Com espaços
mensagem="Olá, mundo!"
caminho="/home/usuario/Meus Documentos"

# Com caracteres especiais
senha="pa$$word"
texto='Isto é um $literal (não expande)'

Para tornar uma variável imutável (readonly):

declare -r PI=3.14159
readonly URL="https://exemplo.com"

# Tentativa de alteração gera erro
PI=3.14   # bash: PI: readonly variable

3. Expansão de variáveis

A expansão é o mecanismo que substitui $variavel pelo seu valor. A forma mais básica é com $:

nome="Ana"
echo $nome        # Ana
echo "$nome"      # Ana (preserva espaços)

Use chaves ${variavel} quando precisar delimitar o nome:

prefixo="super"
echo "${prefixo}mercado"   # supermercado
echo "$prefixomercado"     # vazio (interpreta 'prefixomercado')

Expansão indireta permite acessar uma variável cujo nome está em outra:

cor_primaria="azul"
nome_variavel="cor_primaria"
echo ${!nome_variavel}   # azul

O comando eval também faz expansão indireta, mas é menos seguro:

eval echo \$$nome_variavel   # azul

4. Parâmetros de substituição (modificadores)

O Bash oferece operadores poderosos para tratar valores padrão e ausentes:

Operador Descrição Exemplo
${var:-padrao} Usa padrao se var não existir ou for nula echo "${nome:-Visitante}"
${var:=padrao} Atribui padrao se var não existir ou for nula echo "${nome:=Visitante}"
${var:+alternativo} Usa alternativo se var existir e não for nula echo "${nome:+presente}"
${var:?mensagem} Exibe erro se var não existir ou for nula echo "${nome:?variável obrigatória}"

Para obter o tamanho de uma string:

texto="Bash Script"
echo ${#texto}   # 11

Para fatiar strings:

texto="Bash Script"
echo ${texto:0:4}    # Bash
echo ${texto:5:6}    # Script
echo ${texto: -6}    # Script (espaço antes do -6)

5. Expansão de aritmética e comandos

A aritmética no Bash usa $(( expressao )):

a=10
b=3
echo $(( a + b ))   # 13
echo $(( a * b ))   # 30
echo $(( a ** 2 ))  # 100 (potenciação)

O comando let faz o mesmo, mas sem eco:

let resultado=a+b
echo $resultado   # 13

Substituição de comando executa um comando e retorna sua saída:

# Forma antiga (com crases)
data=`date +%Y-%m-%d`

# Forma moderna (recomendada)
data=$(date +%Y-%m-%d)
echo "Hoje é $data"

A forma $(comando) é preferível porque permite aninhamento fácil:

# Aninhamento com $()
arquivo=$(ls -la $(pwd))

# Com crases seria confuso
arquivo=`ls -la \`pwd\``

6. Remoção e substituição de padrões em strings

O Bash permite manipular strings com padrões (globbing):

Remoção de prefixo:

arquivo="documento.txt.bak"
echo ${arquivo#*.}    # txt.bak (menor correspondência)
echo ${arquivo##*.}   # bak (maior correspondência)

Remoção de sufixo:

arquivo="documento.txt.bak"
echo ${arquivo%.*}    # documento.txt (menor)
echo ${arquivo%%.*}   # documento (maior)

Substituição de padrões:

texto="O rato roeu a roupa do rei"
echo ${texto/rato/gato}        # O gato roeu a roupa do rei (primeira ocorrência)
echo ${texto//r/g}             # O gato goeu a goupa do gei (global)
echo ${texto/#O/A}             # A rato roeu a roupa do rei (início)
echo ${texto/%rei/rainha}      # O rato roeu a roupa da rainha (final)

7. Arrays no Bash

Arrays indexados (índices numéricos):

# Declaração
frutas=("maçã" "banana" "laranja")

# Atribuição direta
frutas[3]="uva"

# Acesso
echo ${frutas[0]}      # maçã
echo ${frutas[@]}      # maçã banana laranja uva
echo ${#frutas[@]}     # 4 (tamanho)

Arrays associativos (chaves nomeadas) com declare -A:

declare -A capitais
capitais[SP]="São Paulo"
capitais[RJ]="Rio de Janeiro"
capitais[BA]="Salvador"

echo ${capitais[SP]}   # São Paulo
echo ${!capitais[@]}   # SP RJ BA (chaves)

8. Boas práticas e armadilhas comuns

Sempre use aspas duplas em expansões:

arquivo="meu arquivo.txt"
# Perigoso
rm $arquivo           # tenta remover 'meu' e 'arquivo.txt'
# Correto
rm "$arquivo"         # remove 'meu arquivo.txt'

Escopo com local dentro de funções:

minha_funcao() {
    local var_local="visível apenas aqui"
    global="visível em todo o script"
}

Diferença entre variável não definida, nula e vazia:

unset var1           # não definida
var2=""             # definida, mas vazia
var3=" "            # definida, não vazia (contém espaço)

echo ${var1:-padrao}   # padrao
echo ${var2:-padrao}   # padrao
echo ${var3:-padrao}   # ' ' (espaço)

Use set -u no início do script para que variáveis não definidas causem erro, ajudando a detectar bugs.


Referências