Estes são conhecimentos necessários àqueles que fazem uso intensivo do Sed, fazendo programas grandes e/ou complexos.
0.1. Monitorando um arquivo
No Sed da GNU, a partir da versão 3.02.80(*), foi adicionada a opção -u, que significa "unbuffered", ou seja, faz um uso minimalista dos registradores, mostrando a saída o mais rápido possível, tornando possível editar um fluxo interminável como o gerado por um tail -f.
Um exemplo prático seria mostrar apenas as mensagens do sistema relativas às conexões ssh:
prompt$ tail -f /var/log/messages | sed -nu '/sshd/p'
Cuidado com -nu perto de crianças! :)
(*) veja o tópico Nota sobre os adicionais GNU
0.2. Colocando comandos Sed num arquivo
Como os comandos Sed vão ficando extensos e complicados, é conveniente colocá-los num arquivo, com estruturação e comentários.
Você pode espalhar os comandos por várias linhas, trocando o ; por quebras
de linha e colocar comentários precedidos de #. O exemplo de apagar
linhas ficaria:
# programa.sed: apaga algumas linhas # apaga a 5ª linha 5d # apaga a 10ª linha 10d # apaga as linhas que contêm 'estorvo' /estorvo/d
Para dizer ao Sed para utilizar aquele arquivo como fonte de comandos,
basta usar a opção -f
prompt$ sed -f programa.sed texto.txt
0.3. Tornando arquivos Sed executáveis
O interpretador de comandos mais utilizado (bash) sempre procura na primeira linha de um arquivo instruções para executá-lo.
Se um arquivo é um programinha em shell, basta colocar
#!/bin/sh
Na primeira linha para que o bash saiba que deve executá-lo com o
comando /bin/sh. O mesmo funciona para qualquer outro interpretador,
como o Sed. então para tornar um arquivos de comandos Sed
executável basta colocar como primeira linha:
#!/bin/sed -f
E é claro, torná-lo executável:
prompt$ chmod +x programa.sed
E na linha de comando, chame-o normalmente:
prompt$ ./programa.sed texto.txt prompt$ cat texto.txt | ./programa.sed
0.4. Conhecendo os registradores internos
0.4.1. Apresentação
O Sed possui 2 registradores ("buffers") internos, que são usados para a manipulação do texto.
Um deles é o espaço padrão ("pattern space"), que é o registrador utilizado normalmente pelo Sed. É nele que a linha a ser processada é armazenada e manipulada.
O outro é o espaço reserva ("hold space"), que é um registrador auxiliar, inicialmente vazio, que serve para guardar uma cópia da linha original, parte dela, ou agrupar dados diversos de várias linhas.
Há comandos para fazer a troca de dados entre os dois registradores:
h guarda no espaço reserva H guarda (anexando) no espaço reserva g pega o conteúdo do espaço reserva G pega (anexando) o conteúdo do espaço reserva x troca os conteúdos dos 2 registradores
O anexando acima significa "não sobrescreve o conteúdo original", ou
seja, ele mantém o que já tem, e adiciona um \n (quebra de linha),
seguido do texto manipulado. Para entender melhor, veja o exemplo gráfico
a seguir.
0.4.2. Exemplo
Um exemplo didático de uso do espaço reserva é ir guardando nele algumas linhas do texto e mostrá-las depois no final do arquivo:
prompt$ sed '/root/H;$g' /etc/passwd
Ou seja, adicione no espaço reserva (comando H), as linhas que contêm a
palavra root e na última linha do arquivo (endereço $), recupere o
conteúdo do espaço reserva (comando g).
0.4.3. Exemplo gráfico
Como os registradores são a parte mais obscura do Sed (mais por falta de documentação do que por complexidade), merecem uma explicação bem didática. Vamos lá.
Temos os dois registradores vazios: (que daqui pra frente serão chamados apenas de padrão e reserva)
__________________ __________________
| | | |
| | | |
|__________________| |__________________|
espaço padrão espaço reserva
E um arquivo hipotético com o conteúdo: (não são odiosos estes exemplos com frutas?)
laranja uva abacaxi melancia mimosa
E aplicaremos o comando:
sed '/laranja/h ; /uva/g ; /abacaxi/H ; /melancia/G ; /mimosa/x'
Obtendo como resultado:
laranja laranja abacaxi melancia laranja abacaxi laranja abacaxi
Vejamos o que aconteceu. Lida a primeira linha laranja, ela é
imediatamente colocada no padrão para ser manipulada:
__________________ __________________
| | | |
| laranja | | |
|__________________| |__________________|
espaço padrão espaço reserva
O comando direcionado a ela é o h, que guarda uma cópia dela no
reserva:
__________________ __________________
| | | |
| laranja | -- h --> | laranja |
|__________________| |__________________|
espaço padrão espaço reserva
Como mais nenhum comando é relativo à linha laranja, o Sed dá por
encerrado o processamento dessa linha e imprime o conteúdo do padrão na
saída: "laranja".
Beleza, agora ele vai processar a segunda linha, novamente a primeira coisa é colocá-la no padrão, sobrescrevendo o que tinha antes:
__________________ __________________
| | | |
| uva | | laranja |
|__________________| |__________________|
espaço padrão espaço reserva
O reserva, enquanto nenhum outro comando escrever nele, permanecerá o
mesmo. O comando direcionado à linha uva é o g, que pega o conteúdo do
reserva e o coloca no padrão, apagando o que estiver nele (neste caso:
uva):
__________________ __________________
| | | |
| laranja | <-- g -- | laranja |
|__________________| |__________________|
espaço padrão espaço reserva
Novamente, não há mais comandos a ser executados, então imprime na saída o conteúdo do padrão: "laranja".
Indo para a terceira linha e colocando-a no padrão:
__________________ __________________
| | | |
| abacaxi | | laranja |
|__________________| |__________________|
espaço padrão espaço reserva
O comando dessa linha é o H, que tal como o h, guarda o conteúdo do
padrão no reserva, com diferença que ele preserva o conteúdo já
existente dele, separando com um \n:
__________________ __________________
| | | |
| abacaxi | -- H --> | laranja\nabacaxi |
|__________________| |__________________|
espaço padrão espaço reserva
Novamente, chegou ao fim, imprime o padrão: "abacaxi".
a próxima linha é a da melancia:
__________________ __________________
| | | |
| melancia | | laranja\nabacaxi |
|__________________| |__________________|
espaço padrão espaço reserva
E agora vai ficar divertido, aplicando o comando G, que pega o conteúdo
do reserva e anexa ao padrão:
____________________________ __________________
| | | |
| melancia\nlaranja\nabacaxi | <-G-- | laranja\nabacaxi |
|____________________________| |__________________|
espaço padrão espaço reserva
E a saída agora fica "melancia\nlaranja\nabacaxi", com o detalhe que o
Sed troca estes \n por quebras de linha na impressão. Então são 3
linhas na saída. Vá acompanhando com o resultado que já foi cantado
antecipadamente lá em cima.
E finalmente, a última linha:
__________________ __________________
| | | |
| mimosa | | laranja\nabacaxi |
|__________________| |__________________|
espaço padrão espaço reserva
E para ela, o comando que troca o conteúdo dos 2 registradores, o x:
__________________ __________________
| | | |
| laranja\nabacaxi | <-- x ---> | mimosa |
|__________________| |__________________|
espaço padrão espaço reserva
E mostra na saída o padrão, com duas linhas: "laranja" e "abacaxi".
Ufa! Depois dessa não venha me dizer que não sabe como funcionam os registradores internos do Sed ;)
0.4.4. Resumão
- Cada linha nova lida é colocada (sobrescrevendo) no espaço padrão
- Uma vez colocado algo no espaço reserva, fica lá até ser sobrescrito
- O
\né o separador do conteúdo original com o anexo - Na saída, o
\nvira quebra de linha - Registradores são simples! ;)
0.4.5. Fluxograma
Para uma representação gráfica dos fluxos e comandos que manipulam estes registradores, veja o tópico Fluxos dos registradores internos.