A expansão de parâmetros é um recurso poderoso do shell que permite manipular variáveis de forma dinâmica, evitando a necessidade de comandos externos como sed ou awk para operações comuns em strings. Nesta aula, vamos explorar quatro tipos principais de expansão: valores padrão, extração de substring, substituição de padrão e obtenção de comprimento. Essas técnicas são essenciais para escrever scripts mais concisos e eficientes.

Dominar a expansão de parâmetros é fundamental para qualquer profissional que trabalhe com automação em Linux. Além de reduzir a complexidade do código, essas operações são executadas diretamente pelo shell, sem a criação de subprocessos, o que melhora a performance em scripts que processam grandes volumes de dados.

Valores padrão (${var:-})

A expansão ${var:-palavra} retorna o valor de var se ela estiver definida e não for nula; caso contrário, retorna palavra. Isso é útil para fornecer valores padrão sem modificar a variável original. Existe também ${var:=palavra}, que atribui o valor padrão à variável se ela não estiver definida.

Por exemplo, em um script que aceita um diretório de saída opcional, podemos usar ${OUTPUT_DIR:-/tmp} para usar /tmp se a variável não for definida. Já ${var:+palavra} retorna palavra se a variável estiver definida e não nula, caso contrário retorna nulo. E ${var:?mensagem} exibe uma mensagem de erro e termina o script se a variável não estiver definida.

#!/bin/bash
# Exemplo de valores padrão
nome=""
echo "Olá, ${nome:-visitante}!"  # Saída: Olá, visitante!
nome="Maria"
echo "Olá, ${nome:-visitante}!"  # Saída: Olá, Maria!

# Usando := para atribuir valor padrão
echo "Antes: ${data:=hoje}"  # data não definida, assume 'hoje' e atribui
echo "Depois: $data"          # Saída: hoje

# Usando :? para abortar se variável não definida
# Descomente a linha abaixo para testar:
# echo "Arquivo: ${arquivo:?Arquivo não especificado}"

Substring

A expansão ${var:posição} retorna a substring de var a partir de posição (base 0). ${var:posição:comprimento} retorna até comprimento caracteres. Se posição for negativo, conta a partir do final da string (requer um espaço ou parênteses para evitar ambiguidade com ${var:-}).

Essa funcionalidade elimina a necessidade de usar cut ou expr substr em muitos casos. Por exemplo, para extrair a extensão de um arquivo: ${arquivo##*.} é mais comum, mas substring também pode ser usado se soubermos a posição do ponto.

#!/bin/bash
frase="Aprendendo Shell Script"
echo "${frase:11}"          # Saída: Shell Script
echo "${frase:11:5}"        # Saída: Shell
echo "${frase: -6}"         # Saída: Script (note o espaço antes do -6)
echo "${frase: -6:3}"       # Saída: Scr

Substituição de padrão

O shell permite substituir partes de uma string que correspondam a um padrão. ${var/padrão/substituto} substitui a primeira ocorrência; ${var//padrão/substituto} substitui todas. ${var/#padrão/substituto} substitui se o padrão estiver no início; ${var/%padrão/substituto} substitui se estiver no final.

Essas operações são muito usadas para manipular caminhos de arquivos, renomear arquivos em lote, ou limpar strings. Por exemplo, ${caminho%/*} retorna o diretório pai (removendo o menor sufixo que corresponda a /*), e ${caminho##*/} retorna o nome do arquivo.

#!/bin/bash
url="https://exemplo.com/arquivo.txt"
echo "${url#*/}"            # Remove a parte até a primeira barra: /exemplo.com/arquivo.txt
echo "${url##*/}"           # Remove até a última barra: arquivo.txt
echo "${url%/*}"            # Remove a última barra e tudo após: https://exemplo.com
echo "${url%.*}"            # Remove a extensão: https://exemplo.com/arquivo

# Substituir todas as ocorrências de 'e' por 'E'
echo "${url//e/E}"          # Saída: https://ExEmplo.com/arquivo.txt

Comprimento

O comprimento de uma string é obtido com ${#var}. Isso retorna o número de caracteres. É útil para validações (tamanho mínimo/máximo) ou para iterar sobre strings.

Para arrays, ${#array[@]} retorna o número de elementos, e ${#array[i]} retorna o comprimento do elemento no índice i.

#!/bin/bash
frase="Olá, mundo!"
echo "Comprimento: ${#frase}"  # Saída: 12

# Array
arr=("um" "dois" "três")
echo "Número de elementos: ${#arr[@]}"  # Saída: 3
echo "Comprimento do primeiro: ${#arr[0]}"  # Saída: 2

Boas práticas

Sempre use aspas duplas ao redor das expansões para preservar espaços e evitar word splitting. Por exemplo, "${var:-padrão}". Prefira ${var:-} a ${var-} quando quiser tratar strings vazias como não definidas. Use ${var:?} para validar parâmetros obrigatórios.

Referências

Exercícios

  1. Escreva um comando que, dada a variável nome="João Silva", exiba "Olá, João!" usando expansão de parâmetros para extrair o primeiro nome.
  2. ✓ Resposta:
    echo "Olá, ${nome%% *}!"

    Explicação: ${nome%% *} remove o maior sufixo que começa com espaço, deixando apenas o primeiro nome.

  3. Usando a variável caminho="/home/usuario/documentos/arquivo.txt", extraia apenas o diretório (sem o nome do arquivo) usando expansão de parâmetros.
  4. ✓ Resposta:
    echo "${caminho%/*}"

    Explicação: ${caminho%/*} remove o menor sufixo que corresponde a /*, ou seja, a última barra e tudo após.

  5. Crie uma variável texto="O rato roeu a roupa do rei de Roma" e substitua todas as ocorrências de "ro" por "**" usando expansão de parâmetros.
  6. ✓ Resposta:
    echo "${texto//ro/**}"

    Explicação: ${texto//ro/**} substitui globalmente todas as ocorrências de "ro" por "**".

  7. Dada a variável data="2024-12-25", extraia o mês (dois dígitos) usando substring.
  8. ✓ Resposta:
    echo "${data:5:2}"

    Explicação: O mês começa na posição 5 (base 0) e tem comprimento 2.

  9. Escreva um script que verifique se a variável ARQUIVO está definida e não é vazia; se não estiver, exiba uma mensagem de erro e saia com código 1. Use expansão de parâmetros.
  10. ✓ Resposta:
    : "${ARQUIVO:?Erro: ARQUIVO não definido ou vazio}"

    Explicação: O comando : (no-op) é usado para que a expansão seja avaliada. Se a variável for nula ou não definida, o shell exibe a mensagem e termina com código 1.