Ubuntu sed

O sed (de stream editor, "editor de fluxo") edita texto sem abrir o arquivo num editor. Você descreve a mudança, como "troque 8080 por 9090", e ele aplica em todas as linhas. É a ferramenta para mudar configurações em scripts e fazer substituições em massa.

Você vai aprender
  • Como o sed processa o texto, linha por linha.
  • A ler e escrever o comando s/procurar/trocar/ parte por parte.
  • A diferença entre mostrar o resultado e alterar o arquivo (-i), e como fazer backup antes.
  • A escolher linhas (endereços), apagar, imprimir e inserir linhas.

O simulador do guia não tem o sed. Os exemplos abaixo são sessões reais do Ubuntu 26.04 (GNU sed 4.9); para praticar, abra o seu terminal.


Como o sed trabalha

O sed lê o texto uma linha por vez. Para cada linha, aplica os seus comandos e escreve o resultado na saída. Depois passa para a próxima linha.

  arquivo ──► [ lê a linha ] ──► [ aplica os comandos ] ──► [ escreve na tela ] ──┐
                   ▲                                                              │
                   └────────────────────── próxima linha ◄────────────────────────┘

Duas consequências importantes:

  • Por padrão, o resultado vai para a tela. O arquivo original não muda.
  • O sed funciona com arquivos de qualquer tamanho, porque nunca carrega o arquivo inteiro.

Nos exemplos, vamos usar estes dois arquivos:

$ cat frutas.txt
banana
maçã
laranja
banana
uva
$ cat app.conf
caminho=/home/ana/fotos
porta=8080
# comentário

nome=loja

Substituir texto: o comando s

O uso mais comum do sed é substituir. Primeiro, a linha inteira:

sed
O programa.
's/banana/BANANA/'
O script, ou seja, a instrução para o sed. Fica entre aspas simples para o shell não mexer nos símbolos.
frutas.txt
O arquivo a ler. Sem ele, o sed lê a entrada (por exemplo, de um pipe).

Agora, o script por dentro. As barras / separam as partes:

s
O comando: substitute, "substituir".
/banana
O que procurar. Pode ser uma expressão regular.
/BANANA
Pelo que trocar.
/
Fim. Depois da última barra vêm as flags (opcionais), como g.
$ sed 's/banana/BANANA/' frutas.txt
BANANA                 « trocou
maçã
laranja
BANANA                 « trocou
uva
$ cat frutas.txt
banana                 « o arquivo continua igual
maçã
laranja
banana
uva

Todas as ocorrências da linha: flag g

Sem flag, o sed troca só a primeira ocorrência de cada linha. A flag g (de global) troca todas:

$ echo "a a a" | sed 's/a/X/'
X a a
$ echo "a a a" | sed 's/a/X/g'
X X X
$ echo "a a a" | sed 's/a/X/2'
a X a                  « um número troca só a 2ª ocorrência

Ignorar maiúsculas e minúsculas: flag I

$ echo "Olá Mundo" | sed 's/mundo/Ubuntu/'
Olá Mundo              « não achou: "mundo" ≠ "Mundo"
$ echo "Olá Mundo" | sed 's/mundo/Ubuntu/I'
Olá Ubuntu

Alterar o arquivo de verdade: -i

A opção -i (de in-place, "no lugar") grava o resultado no próprio arquivo, em vez de mostrar na tela.

sed
O programa.
-i.bak
Edita o arquivo e guarda uma cópia do original com a extensão .bak.
's/porta=8080/porta=9090/'
A substituição.
app.conf
O arquivo que será alterado.
$ sed -i.bak 's/porta=8080/porta=9090/' app.conf
$ ls
app.conf  app.conf.bak  frutas.txt
$ grep porta app.conf app.conf.bak
app.conf:porta=9090             « o arquivo mudou
app.conf.bak:porta=8080         « a cópia guarda o original
Teste antes de usar -i

Rode primeiro sem -i e confira a saída. Só depois acrescente o -i. Com -i sozinho (sem .bak), não existe "desfazer".

Formas diferentes de salvar o resultado

FormaExemploQuando usar
Só olharsed 's/a/b/' arqSempre, primeiro, para testar.
Novo arquivosed 's/a/b/' arq > novoQuer manter o original intacto.
No lugar, com backupsed -i.bak 's/a/b/' arqMudança em configuração: dá para voltar.
No lugar, sem backupsed -i 's/a/b/' arqScripts testados, arquivos que você pode recriar.
Nunca use sed … arq > arq

O > esvazia o arquivo antes de o sed ler, e você perde tudo. Veja Redirecionamento.


Caminhos com barras: troque o separador

Para trocar /home/ana por /home/bia, as barras do caminho se misturam com as barras do comando:

$ sed 's//home/ana//home/bia/' app.conf
sed: -e expressão #1, caractere 9: opção desconhecida para o comando `s' (s///?)

O sed aceita qualquer caractere como separador: é o primeiro que aparece depois do s. Use | ou #:

$ sed 's|/home/ana|/home/bia|' app.conf
caminho=/home/bia/fotos
porta=8080
# comentário

nome=loja

Outra forma é "escapar" cada barra com \: sed 's/\/home\/ana/\/home\/bia/'. Funciona, mas é bem mais difícil de ler.


Padrões: expressões regulares

O que você procura pode ser um padrão, e não só um texto fixo. Os símbolos mais usados:

SímboloSignificaExemplo
.Qualquer caracterec.sa casa com "casa" e "cosa"
*O anterior, zero ou mais vezesporta=.* = "porta=" e qualquer coisa depois
^Começo da linha^# = linha que começa com #
$Fim da linha^$ = linha vazia
[0-9]Um caractere da lista[0-9] = um dígito
\+O anterior, uma ou mais vezes[0-9]\+ = um número
&Na troca: o texto encontrados/[0-9]\+/[&]/ põe o número entre colchetes

Trocar o valor da porta, seja ele qual for:

$ sed 's/porta=.*/porta=9090/' app.conf
caminho=/home/ana/fotos
porta=9090
# comentário

nome=loja
$ sed 's/[0-9]\+/[&]/' app.conf | head -n 2
caminho=/home/ana/fotos
porta=[8080]                    « & repetiu o número encontrado

Grupos e expressões estendidas: -E

Com -E, você usa parênteses para guardar partes do que foi encontrado e devolvê-las com \1, \2…

$ sed -E 's/([a-z]+)=(.*)/\2 <- \1/' app.conf | head -n 2
/home/ana/fotos <- caminho
8080 <- porta

Aqui, ([a-z]+) guardou o nome (grupo 1) e (.*) guardou o valor (grupo 2). Na troca, eles foram escritos em ordem invertida.


Escolher linhas: endereços

Antes de um comando, você pode dizer em quais linhas ele vale. Isso se chama endereço.

EndereçoLinhasExemplo
3Só a linha 3sed '3s/a/b/'
2,4Da 2 à 4sed '2,4d'
$A últimased '$d'
/padrão/As que contêm o padrãosed '/porta/s/8080/80/'
/ini/,/fim/De uma linha com "ini" até uma com "fim"sed -n '/\[db\]/,/^$/p'

Apagar linhas: d

O comando d (de delete) não escreve a linha. Um uso muito comum é ver uma configuração sem comentários nem linhas vazias:

sed
O programa.
'/^#/d
Apaga as linhas que começam com #…
;
…e depois (o ponto e vírgula separa comandos)…
/^$/d'
…apaga as linhas vazias.
app.conf
O arquivo.
$ sed '/^#/d; /^$/d' app.conf
caminho=/home/ana/fotos
porta=8080
nome=loja

Imprimir só algumas linhas: -n + p

A opção -n desliga a impressão automática. O comando p (de print) imprime a linha. Juntos, mostram só o que você escolheu:

$ sed -n '2,3p' frutas.txt
maçã
laranja
$ sed -n '/porta/p' app.conf
porta=8080
$ sed -n '$=' app.conf
5                               « o comando = mostra o número da linha; aqui, a última

Inserir e acrescentar linhas: i e a

$ sed '1i # Arquivo gerado automaticamente' app.conf | head -n 2
# Arquivo gerado automaticamente
caminho=/home/ana/fotos
$ sed '$a debug=false' app.conf | tail -n 2
nome=loja
debug=false

1i insere antes da linha 1; $a acrescenta depois da última.


Formas diferentes de ver um arquivo sem comentários

ComandoObservação
sed '/^#/d; /^$/d' arqUm programa só, dois comandos.
grep -v '^#' arq | grep -v '^$'Mais fácil de ler para iniciantes.
grep -Ev '^(#|$)' arqO mais curto. Veja grep.
awk '!/^#/ && NF' arqCom awk: não começa com # e tem algum campo. Veja awk.

Quando não funciona

"comando `s' não terminado"
$ sed 's/banana/BANANA' frutas.txt
sed: -e expressão #1, caractere 15: comando `s' não terminado

O que aconteceu: faltou a última barra. O comando s precisa de três: s/a/b/.

Como resolver: sed 's/banana/BANANA/' frutas.txt. O número do "caractere" diz onde o sed se perdeu.

"opção desconhecida para o comando `s'"

O que aconteceu: o texto tem barras /, como um caminho, e o sed achou que o comando acabou antes.

Como resolver: troque o separador: sed 's|/opt/app|/srv/app|'.

"Permissão negada" com -i
$ sed -i 's/notebook/estudio/' /etc/hostname
sed: não foi possível abrir o arquivo temporário /etc/sedrkIxCO: Permissão negada

O que aconteceu: o -i cria um arquivo temporário na mesma pasta e depois troca pelo original. Em /etc, só o root pode criar arquivos.

Como resolver: teste sem -i, depois rode com sudo e backup: sudo sed -i.bak 's/notebook/estudio/' /etc/hostname.

Não deu erro, mas não trocou nada

O que aconteceu: o padrão não casou. As causas mais comuns são maiúsculas diferentes ("Mundo" × "mundo"), espaços a mais, ou símbolos especiais. Por exemplo, o ponto em s/1.0/2.0/ significa "qualquer caractere".

Como confirmar: procure o padrão com grep antes: grep -n 'mundo' arquivo. Se o grep não acha, o sed também não vai achar.

Como resolver: use a flag I para ignorar maiúsculas, e escape símbolos especiais com \: s/1\.0/2.0/.

Uma variável não foi trocada pelo valor
$ novo=9090
$ sed 's/8080/$novo/' app.conf | grep porta
porta=$novo

O que aconteceu: dentro de aspas simples, o shell não troca variáveis.

Como resolver: use aspas duplas: sed "s/8080/$novo/" app.conf.


Referência

Opções

OpçãoDescriçãoExemplo
-nNão imprime automaticamente (use com p)sed -n '5p' arq
-iEdita o próprio arquivosed -i 's/a/b/' arq
-i.bakEdita e guarda o original como .baksed -i.bak 's/a/b/' arq
-EExpressões regulares estendidas (+ ? ( ) | sem barra)sed -E 's/(a|b)+/X/'
-eAcrescenta um comando (pode repetir)sed -e 's/a/b/' -e '/^$/d'

Comandos

ComandoDescriçãoExemplo
s/a/b/Substitui a primeira ocorrência por linhased 's/http/https/'
s/a/b/gSubstitui todassed 's/ /_/g'
s/a/b/IIgnora maiúsculassed 's/erro/ERRO/I'
dApaga a linhased '/^#/d'
pImprime a linhased -n '/erro/p'
i textoInsere antessed '1i Título'
a textoAcrescenta depoissed '$a Fim'
=Mostra o número da linhased -n '$='
qSai (para de ler)sed '10q' (como head)
y/abc/ABC/Troca caractere por caracteresed 'y/abc/ABC/'

Exercícios

1. Trocar todas

Complete para trocar todos os espaços de cada linha por _:

sed 's/ /_/' nomes.txt

2. Editar com segurança

Complete para alterar app.conf no lugar, guardando uma cópia .bak:

sed 's/debug=true/debug=false/' app.conf

3. Só as linhas de erro

Complete para mostrar só as linhas que contêm "erro":

sed '/erro/' sistema.log

4. Você rodou sed 's/8080/9090/' app.conf e a tela mostrou "porta=9090". O que aconteceu com o arquivo?

5. Qual comando troca o caminho /var/www por /srv/www sem dar erro?


Resumo

  • O sed lê linha por linha e mostra o resultado; o arquivo só muda com -i.
  • s/procurar/trocar/ troca a primeira ocorrência por linha; g troca todas.
  • Teste sem -i, depois use -i.bak para ter como voltar.
  • Com barras no texto, troque o separador: s|a|b|.
  • Endereços escolhem linhas; d apaga, -n … p imprime só o que você quer.