Dicas para usar sed em substituições em lote com backup automático

1. Introdução ao sed e à importância do backup automático

O sed (stream editor) é uma ferramenta Unix essencial para processamento de texto em lote. Sua capacidade de realizar substituições automáticas em múltiplos arquivos o torna indispensável para administradores de sistemas, desenvolvedores e profissionais de dados que precisam modificar rapidamente grandes volumes de arquivos de configuração, código-fonte ou documentos.

No entanto, substituições em massa carregam riscos significativos. Um padrão de expressão regular mal construído pode corromper centenas de arquivos em segundos. Já presenciei casos em que uma substituição aparentemente inofensiva como s/foo/bar/g transformou "food" em "bard" ou "football" em "bartball". O backup automático não é apenas uma boa prática — é uma necessidade absoluta para qualquer operação de substituição em lote.

2. Sintaxe básica do sed para substituições seguras

A estrutura fundamental do sed para substituições é:

sed 's/padrão/substituição/' arquivo

A flag -i (in-place) modifica o arquivo diretamente, mas sem backup é perigosa:

# PERIGOSO - sem backup
sed -i 's/antigo/novo/g' config.txt

A flag g (global) substitui todas as ocorrências em cada linha, não apenas a primeira:

# Substitui apenas a primeira ocorrência por linha
sed -i 's/erro/correcao/' log.txt

# Substitui todas as ocorrências
sed -i 's/erro/correcao/g' log.txt

3. Criando backups automáticos com a extensão de backup do sed

A opção mais simples para backup automático é adicionar uma extensão ao -i:

sed -i.bak 's/foo/bar/g' arquivo.txt

Isso cria arquivo.txt.bak contendo o conteúdo original antes da modificação. Exemplos práticos:

# Backup com extensão .bak
sed -i.bak 's/localhost/192.168.1.100/g' hosts.txt

# Backup com extensão .original
sed -i.original 's/DEBUG=false/DEBUG=true/g' .env

# Backup com extensão .backup
sed -i.backup 's/versao_antiga/versao_nova/g' app.conf

Para operações em lote com múltiplos arquivos:

# Substituição em todos os arquivos .txt com backup individual
for arquivo in *.txt; do
    sed -i.bak "s/antigo/novo/g" "$arquivo"
done

4. Estratégias avançadas de backup para operações em lote

Combinando sed com find para substituições recursivas:

# Substituição recursiva em todos os .html com backup
find . -name "*.html" -exec sed -i.bak 's/http:\/\/antigo/http:\/\/novo/g' {} +

Backups com data e timestamp para rastreabilidade:

# Backup com data no formato YYYYMMDD
find . -name "*.py" -exec sed -i.backup_$(date +%Y%m%d) 's/print(/log.info(/g' {} +

Script que verifica backup existente antes de modificar:

#!/bin/bash
ARQUIVO="config.yaml"
BACKUP="${ARQUIVO}.bak"

if [ ! -f "$BACKUP" ]; then
    cp "$ARQUIVO" "$BACKUP"
    echo "Backup criado: $BACKUP"
fi

sed -i 's/porta_antiga/porta_nova/g' "$ARQUIVO"

5. Lidando com padrões complexos e substituições condicionais

Expressões regulares estendidas (-E) com backup automático:

# Substitui endereços IP (padrão: 3 dígitos.3 dígitos.3 dígitos.3 dígitos)
sed -i.bak -E 's/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/10.0.0.1/g' network.conf

Backreferences preservando partes do padrão:

# Converte "nome: joao" para "NOME: JOAO" mantendo a estrutura
sed -i.bak -E 's/(nome|email): ([a-z]+)/\U\1: \U\2/g' usuarios.txt

Teste seguro sem backup antes de aplicar:

# Teste apenas visual (sem -i)
sed 's/antigo/novo/g' arquivo.txt | head -20

# Se ok, aplica com backup
sed -i.bak 's/antigo/novo/g' arquivo.txt

6. Recuperação de dados a partir dos backups gerados

Restauração rápida de um único arquivo:

# Restaurar arquivo.txt do backup .bak
cp arquivo.txt.bak arquivo.txt

Script para reverter múltiplas alterações em lote:

#!/bin/bash
# Reverte todos os backups .bak para arquivos originais
for bak in *.bak; do
    original="${bak%.bak}"
    if [ -f "$original" ]; then
        cp "$bak" "$original"
        echo "Restaurado: $original"
    fi
done

Organizando backups em diretório separado:

#!/bin/bash
DIR_BACKUP="backups_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$DIR_BACKUP"

for arquivo in *.txt; do
    cp "$arquivo" "$DIR_BACKUP/"
    sed -i.bak 's/antigo/novo/g' "$arquivo"
done

echo "Backups salvos em: $DIR_BACKUP"

7. Boas práticas e automação com scripts shell

Função shell para substituições com backup obrigatório:

substituir_com_backup() {
    local padrao="$1"
    local substituicao="$2"
    local arquivo="$3"
    local backup_dir="backups_auto"

    mkdir -p "$backup_dir"
    cp "$arquivo" "${backup_dir}/${arquivo}.$(date +%Y%m%d_%H%M%S)"
    sed -i.bak "s/$padrao/$substituicao/g" "$arquivo"
    echo "Backup em: ${backup_dir}/${arquivo}.$(date +%Y%m%d_%H%M%S)"
}

Script que valida integridade do backup:

#!/bin/bash
validar_backup() {
    local original="$1"
    local backup="${original}.bak"

    if [ ! -f "$backup" ]; then
        echo "ERRO: Backup não encontrado!" >&2
        exit 1
    fi

    # Verifica se o backup tem conteúdo
    if [ ! -s "$backup" ]; then
        echo "ERRO: Backup vazio!" >&2
        exit 1
    fi

    echo "Backup válido: $backup"
}

# Uso
validar_backup "config.ini"
sed -i.bak 's/antigo/novo/g' config.ini

Integração com git para auditoria:

#!/bin/bash
# Substituição com commit automático no git
git add .
git commit -m "Backup antes da substituição em lote"

sed -i.bak 's/API_KEY_ANTIGA/API_KEY_NOVA/g' *.env

git add .
git commit -m "Substituição: API_KEY_ANTIGA -> API_KEY_NOVA"

8. Considerações finais e troubleshooting

Erros comuns por sistema:

No macOS, o sed BSD requer um argumento para -i:

# Linux (GNU sed) - funciona
sed -i.bak 's/foo/bar/g' arquivo.txt

# macOS (BSD sed) - requer espaço ou aspas
sed -i '.bak' 's/foo/bar/g' arquivo.txt
# ou
sed -i '' 's/foo/bar/g' arquivo.txt  # sem backup

Evitando sobrescrita acidental de backups:

#!/bin/bash
ARQUIVO="$1"
BACKUP="${ARQUIVO}.bak"

if [ -f "$BACKUP" ]; then
    echo "Backup já existe: $BACKUP"
    echo "Deseja sobrescrever? (s/N)"
    read resposta
    if [ "$resposta" != "s" ] && [ "$resposta" != "S" ]; then
        echo "Operação cancelada."
        exit 1
    fi
fi

sed -i.bak 's/antigo/novo/g' "$ARQUIVO"

Checklist para substituições seguras:

  1. ✅ Teste o padrão com sed sem -i primeiro
  2. ✅ Verifique a saída em 3-5 arquivos representativos
  3. ✅ Configure backup automático com extensão
  4. ✅ Execute em lote pequeno primeiro
  5. ✅ Verifique alguns arquivos modificados
  6. ✅ Mantenha backups até próxima validação

Lembre-se: um backup bem feito é a diferença entre um problema resolvido e uma catástrofe de dados. O sed é poderoso, mas com grandes poderes vêm grandes responsabilidades — e backups automáticos.

Referências

8. Considerações finais e troubleshooting

Erros comuns por sistema:

No macOS, o sed BSD requer um argumento para -i:

# Linux (GNU sed) - funciona
sed -i.bak 's/foo/bar/g' arquivo.txt

# macOS (BSD sed) - requer espaço ou aspas
sed -i '.bak' 's/foo/bar/g' arquivo.txt
# ou
sed -i '' 's/foo/bar/g' arquivo.txt  # sem backup

Evitando sobrescrita acidental de backups:

#!/bin/bash
ARQUIVO="$1"
BACKUP="${ARQUIVO}.bak"

if [ -f "$BACKUP" ]; then
    echo "Backup já existe: $BACKUP"
    echo "Deseja sobrescrever? (s/N)"
    read resposta
    if [ "$resposta" != "s" ] && [ "$resposta" != "S" ]; then
        echo "Operação cancelada."
        exit 1
    fi
fi

sed -i.bak 's/antigo/novo/g' "$ARQUIVO"

Checklist para substituições seguras:

  1. ✅ Teste o padrão com sed sem -i primeiro
  2. ✅ Verifique a saída em 3-5 arquivos representativos
  3. ✅ Configure backup automático com extensão
  4. ✅ Execute em lote pequeno primeiro
  5. ✅ Verifique alguns arquivos modificados
  6. ✅ Mantenha backups até próxima validação

Lembre-se: um backup bem feito é a diferença entre um problema resolvido e uma catástrofe de dados. O sed é poderoso, mas com grandes poderes vêm grandes responsabilidades — e backups automáticos.

Referências