Fundamentos do sed: Substituição de Texto com o Editor de Fluxo

Fundamentos do sed: Substituição de Texto com o Editor de Fluxo

O Que Você Vai Aprender

  • Os cinco padrões essenciais do sed (substituir / deletar / imprimir / endereço / multi-expressão) no caminho mais curto para fluência
  • O padrão seguro para edições -i (in-place) para parar de destruir arquivos
  • A diferença entre BRE e ERE (-E) para que seu regex fique consistente com grep -E e awk

O padrão prático

  • Sempre visualize na saída padrão primeiro, depois confirme com -i.bak
  • O delimitador não precisa ser / -- use | ou # ao reescrever caminhos
  • Esquecer a flag g no final significa que apenas a primeira correspondência por linha será substituída

Premissas

  • SO: Ubuntu / Debian / família RHEL Linux
  • Versão do sed: GNU sed (BSD sed no macOS usa sintaxe diferente para -i -- consulte a documentação do fornecedor)

O Que é o sed?

sed (editor de fluxo) lê a entrada linha por linha, aplica um script de edição e escreve na saída padrão. Diferente de editores interativos como o Vim, o sed foi feito para uso não interativo dentro de pipelines do shell -- normalização de logs, reescrita de configurações, preprocessamento de texto.

$ echo "hello world" | sed 's/world/Linux/'
hello Linux

O comando s/old/new/ (substituição) representa aproximadamente 80% do uso real do sed.

Por Que Visualizar na Saída Padrão Primeiro?

sed -i sobrescreve o arquivo diretamente. Se você perceber depois que o padrão estava errado ou esqueceu de escapar uma /, a recuperação é difícil. Sempre visualize na saída padrão, depois confirme com -i.bak -- este é o único hábito confiável.

# 1. Visualizar na saida padrao
$ sed 's/foo/bar/g' config.txt

# 2. Confirmar com backup
$ sed -i.bak 's/foo/bar/g' config.txt

# 3. config.txt.bak e gerado automaticamente
$ ls config.txt*
config.txt  config.txt.bak

Usar -i sem sufixo de backup é arriscado para trabalho em produção. Torne -i.bak um hábito -- reverter é apenas mv config.txt.bak config.txt.

1. Substituição: s/old/new/

1-1. Primeira correspondência em cada linha (padrão)

$ echo "apple apple apple" | sed 's/apple/orange/'
orange apple apple

1-2. Todas as correspondências na linha (flag g)

$ echo "apple apple apple" | sed 's/apple/orange/g'
orange orange orange

Esquecer o g é o erro #1 do sed. Se "apenas algumas correspondências mudaram," verifique primeiro se falta o g.

1-3. Sem diferenciar maiúsculas/minúsculas (flag I)

$ echo "Apple APPLE apple" | sed 's/apple/orange/gI'
orange orange orange

A flag I é uma extensão do GNU sed. Evite-a em scripts portáveis (o sed POSIX não a suporta).

2. Mudando o Delimitador de /

Quando o padrão contém caminhos como /usr/local, escapar cada / rapidamente se torna ilegível. O caractere logo após s é o delimitador -- escolha |, # ou , para manter a legibilidade.

# Ruim: inferno de barras invertidas
$ sed 's/\/usr\/local\/bin/\/opt\/bin/' file

# Bom: pipe como delimitador
$ sed 's|/usr/local/bin|/opt/bin|' file

# Tambem bom: hash como delimitador
$ sed 's#/usr/local/bin#/opt/bin#' file

Mudar o delimitador elimina 80% dos bugs de substituição. Para reescrita de caminhos, | ou # é o padrão de fato.

3. Endereços: Direcionando Linhas Específicas

Todo comando de edição do sed pode receber um prefixo de endereço que restringe em quais linhas ele é aplicado.

3-1. Por número de linha

$ sed '3s/foo/bar/' file       # Apenas linha 3
$ sed '1,5s/foo/bar/g' file    # Linhas 1-5
$ sed '10,$s/foo/bar/g' file   # Linha 10 ate o final ($ = ultima linha)

3-2. Por padrão

# Apenas em linhas contendo "ERROR"
$ sed '/ERROR/s/foo/bar/g' file

# Entre /START/ e /END/
$ sed '/START/,/END/s/foo/bar/g' file

3-3. Negação (!)

# Todas as linhas exceto a linha 1
$ sed '1!s/foo/bar/g' file

# Tudo exceto linhas de comentario (comecando com #)
$ sed '/^#/!s/foo/bar/g' file

4. Deletar (d) e Imprimir (p)

4-1. Deletar linhas

$ sed '/^$/d' file              # Deletar linhas vazias
$ sed '/^#/d' file              # Deletar linhas de comentario
$ sed '1,5d' file               # Deletar linhas 1-5
$ sed '$d' file                 # Deletar a ultima linha

4-2. Imprimir apenas linhas específicas (-n + p)

Por padrão, o sed imprime todas as linhas. A flag -n suprime a saída padrão, então você só vê as linhas que explicitamente imprimir com p.

# Imprimir linhas contendo "ERROR" (como grep "ERROR")
$ sed -n '/ERROR/p' file

# Imprimir linhas 10-20
$ sed -n '10,20p' file

sed -n 'Np' é mais rápido e claro que head -n N | tail -1 para extrair uma única linha.

5. Múltiplas Edições em Uma Passagem

5-1. Múltiplas expressões -e

$ sed -e 's/foo/bar/g' -e 's/hoge/fuga/g' file

5-2. Separadas por ponto e vírgula (GNU sed)

$ sed 's/foo/bar/g; s/hoge/fuga/g' file

5-3. Arquivo de script com -f

Salve conjuntos de transformações reutilizáveis em um arquivo.

$ cat replace.sed
s/foo/bar/g
s/hoge/fuga/g
/^#/d

$ sed -f replace.sed file

6. BRE vs ERE: Devo Sempre Usar -E?

O sed usa por padrão BRE (Expressões Regulares Básicas). Usar +, ?, | ou (...) requer escape com barra invertida, o que fica feio rapidamente. Adicionar -E muda para ERE (Expressões Regulares Estendidas) -- a mesma variante que grep -E e awk usam.

6-1. BRE (padrão)

# Grupos e quantificadores requerem \( \) e \{ \}
$ echo "2026-05-20" | sed 's/\([0-9]\{4\}\)-\([0-9]\{2\}\)-\([0-9]\{2\}\)/\3\/\2\/\1/'
20/05/2026

6-2. ERE (-E)

# Sem escape -- muito mais facil de ler
$ echo "2026-05-20" | sed -E 's/([0-9]{4})-([0-9]{2})-([0-9]{2})/\3\/\2\/\1/'
20/05/2026

Torne -E seu padrão. O escape do BRE coloca carga cognitiva nos revisores e leva a bugs passando despercebidos.

6-3. Retro-referências (\1, \2, ...)

Grupos capturados são referenciados como \1, \2, etc. na substituição. Mesma sintaxe em BRE e ERE.

# "Sobrenome, Nome" -> "Nome Sobrenome"
$ echo "Doe, John" | sed -E 's/(.+), (.+)/\2 \1/'
John Doe

7. Armadilhas e Como Evitá-las

Top 5 armadilhas do sed

  1. Executar -i sem visualizar -- irrecuperável. Sempre visualize primeiro, depois use -i.bak
  2. Flag g ausente -- apenas uma correspondência por linha é alterada
  3. Esquecer de mudar o delimitador -- escape de / torna padrões ilegveis
  4. Misturar BRE e ERE -- escolha um e mantenha (-E recomendado)
  5. Tratar * ou . como literais -- são metacaracteres regex; escape-os

7-1. Escapando metacaracteres literais

# Ruim: . corresponde a qualquer caractere
$ echo "192x168x0x1" | sed 's/192.168.0.1/X/'
X

# Bom: escape o ponto
$ echo "192x168x0x1" | sed 's/192\.168\.0\.1/X/'
192x168x0x1

7-2. Incorporando variáveis do shell

Variáveis do shell não expandem dentro de aspas simples. Mude para aspas duplas -- mas cuidado com $ e \ dentro delas.

NEW="bar"

# Ruim: $NEW e literal
$ sed 's/foo/$NEW/g' file

# Bom: aspas duplas para expansao
$ sed "s/foo/$NEW/g" file

Se $NEW contiver /, & ou \, a substituição quebra. Mude o delimitador ou sanitize o valor antes de injetá-lo.

8. Receitas Práticas

Templates para copiar e colar

# Converter CRLF para LF
sed -i.bak 's/\r$//' file

# Remover linhas vazias e comentarios #
sed -e '/^$/d' -e '/^#/d' /etc/nginx/nginx.conf

# Mascarar enderecos IP
sed -E 's/\b([0-9]{1,3}\.){3}[0-9]{1,3}\b/x.x.x.x/g' access.log

# Remover espacos em branco no final
sed -i.bak 's/[[:space:]]*$//' file

# Inserir uma linha antes de linhas correspondentes a um padrao
sed -i.bak '/^pattern/i\
inserted line before' file

# Reescrever um valor YAML (apos chave:)
sed -i.bak -E 's/^(version:\s*).*/\1"1.2.3"/' config.yaml

sed vs awk vs grep: Quando Usar Qual

Tarefa Melhor ferramenta
Substituição simples de strings sed
Filtrar linhas correspondentes (grep-like) grep / sed -n
Processamento por colunas (campos, soma) awk
Transformações multi-linha sed comando N ou awk
Dados estruturados (JSON / YAML) jq / yq

sed brilha em: edições de linha única em fluxo, baixo consumo de memória, disponível em todo Unix sed tem dificuldade com: dados colunares, formatos estruturados, lógica multi-linha -- mude para awk ou jq quando as coisas ficarem complexas

O Que Ler em Seguida