Pesquisa de site

O básico do uso do Sed Stream Editor para manipular texto no Linux


Introdução

O comando sed, abreviação de stream editor, executa operações de edição em texto proveniente de entrada padrão ou de um arquivo. sed edita linha por linha e de forma não interativa.

Isso significa que você toma todas as decisões de edição enquanto chama o comando e sed executa as instruções automaticamente. Isso pode parecer confuso ou pouco intuitivo, mas é uma maneira muito poderosa e rápida de transformar texto, especialmente como parte de um script ou fluxo de trabalho automatizado.

Este tutorial cobrirá algumas operações básicas e apresentará a sintaxe necessária para operar este editor. É quase certo que você nunca substituirá seu editor de texto comum por sed, mas provavelmente será uma adição bem-vinda à sua caixa de ferramentas de edição de texto.

Observação: este tutorial usa a versão GNU do sed encontrada no Ubuntu e em outros sistemas operacionais Linux. Se você estiver usando o macOS, terá a versão BSD que possui diferentes opções e argumentos. Você pode instalar a versão GNU do sed com o Homebrew usando brew install gnu-sed.

Uso Básico

sed opera em um fluxo de texto que lê de um arquivo de texto ou de uma entrada padrão (STDIN). Isso significa que você pode enviar a saída de outro comando diretamente para o sed para edição ou pode trabalhar em um arquivo que já criou.

Você também deve estar ciente de que sed envia tudo para a saída padrão (STDOUT) por padrão. Isso significa que, a menos que seja redirecionado, sed imprimirá sua saída na tela em vez de salvá-la em um arquivo.

O uso básico é:

  1. sed [options] commands [file-to-edit]

Neste tutorial, você usará uma cópia da licença de software BSD para experimentar o sed. No Ubuntu, execute os seguintes comandos para copiar o arquivo de licença BSD para seu diretório pessoal para poder trabalhar com ele:

  1. cd
  2. cp /usr/share/common-licenses/BSD .

Se você não possui uma cópia local da licença BSD, crie uma você mesmo com este comando:

  1. cat << 'EOF' > BSD
  2. Copyright (c) The Regents of the University of California.
  3. All rights reserved.
  4. Redistribution and use in source and binary forms, with or without
  5. modification, are permitted provided that the following conditions
  6. are met:
  7. 1. Redistributions of source code must retain the above copyright
  8. notice, this list of conditions and the following disclaimer.
  9. 2. Redistributions in binary form must reproduce the above copyright
  10. notice, this list of conditions and the following disclaimer in the
  11. documentation and/or other materials provided with the distribution.
  12. 3. Neither the name of the University nor the names of its contributors
  13. may be used to endorse or promote products derived from this software
  14. without specific prior written permission.
  15. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  16. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  19. FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  21. OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  22. HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  23. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  24. OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  25. SUCH DAMAGE.
  26. EOF

Vamos usar sed para visualizar o conteúdo do arquivo de licença BSD. sed envia seus resultados para a tela por padrão, o que significa que você pode usá-lo como um leitor de arquivos sem passar comandos de edição. Tente executar o seguinte comando:

  1. sed '' BSD

Você verá a licença BSD exibida na tela:

Output
Copyright (c) The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. ... ...

As aspas simples contêm os comandos de edição que você passa para sed. Neste caso, você não passou nada, então sed imprimiu cada linha recebida na saída padrão.

sed pode usar entrada padrão em vez de um arquivo. Encaminhe a saída do comando cat para sed para produzir o mesmo resultado:

  1. cat BSD | sed ''

Você verá a saída do arquivo:

Output
Copyright (c) The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. . . . . . .

Como você pode ver, você pode operar em arquivos ou fluxos de texto, como os produzidos ao canalizar a saída com o caractere pipe (|), com a mesma facilidade.

Linhas de impressão

No exemplo anterior, você viu que a entrada passada para sed sem nenhuma operação imprimiria os resultados diretamente na saída padrão.

Vamos explorar o comando print explícito de sed, que você especifica usando o caractere p entre aspas simples.

Execute o seguinte comando:

  1. sed 'p' BSD

Você verá cada linha do arquivo BSD impressa duas vezes:

Output
Copyright (c) The Regents of the University of California. Copyright (c) The Regents of the University of California. All rights reserved. All rights reserved. Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions modification, are permitted provided that the following conditions are met: are met: . . . . . .

sed imprime automaticamente cada linha por padrão e, em seguida, você o instruiu a imprimir linhas explicitamente com o comando \p, para que cada linha seja impressa duas vezes.

Se você examinar a saída de perto, verá que ela tem a primeira linha duas vezes, seguida pela segunda linha duas vezes, etc., o que informa que sed opera nos dados linha por linha. Ele lê uma linha, opera nela e emite o texto resultante antes de repetir o processo na próxima linha.

Você pode limpar os resultados passando a opção -n para sed, que suprime a impressão automática:

  1. sed -n 'p' BSD
Output
Copyright (c) The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. . . . . . .

Agora voltamos a imprimir cada linha uma vez.

Os exemplos até agora dificilmente podem ser considerados de edição (a menos que você queira imprimir cada linha duas vezes…). Em seguida, você explorará como o sed pode modificar a saída, visando seções específicas dos dados de texto.

Usando Intervalos de Endereço

Os endereços permitem segmentar partes específicas de um fluxo de texto. Você pode especificar uma linha específica ou até mesmo um intervalo de linhas.

Vamos fazer sed imprimir a primeira linha do arquivo. Execute o seguinte comando:

  1. sed -n '1p' BSD

A primeira linha imprime na tela:

Output
Copyright (c) The Regents of the University of California.

Ao colocar o número 1 antes do comando de impressão, você informa ao sed o número da linha para operar. Você pode facilmente imprimir cinco linhas (não se esqueça do \-n):

  1. sed -n '1,5p' BSD

Você verá esta saída:

Output
Copyright (c) The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions

Você acabou de fornecer um intervalo de endereços para sed. Se você der um endereço ao sed, ele executará apenas os comandos que seguem nessas linhas. Neste exemplo, você disse ao sed para imprimir a linha 1 até a linha 5. Você poderia ter especificado isso de uma maneira diferente, fornecendo o primeiro endereço e, em seguida, usando um deslocamento para informar ao sed quantas linhas adicionais devem ser percorridas, assim:

  1. sed -n '1,+4p' BSD

Isso resultará na mesma saída, porque você disse ao sed para começar na linha 1 e então operar nas próximas 4 linhas também.

Se você deseja imprimir linhas alternadas, especifique o intervalo após o caractere ~. O comando a seguir imprime linhas alternadas no arquivo BSD, começando com a linha 1:

  1. sed -n '1~2p' BSD

Aqui está a saída que você verá:

Output
Copyright (c) The Regents of the University of California. modification, are permitted provided that the following conditions 1. Redistributions of source code must retain the above copyright 2. Redistributions in binary form must reproduce the above copyright documentation and/or other materials provided with the distribution. may be used to endorse or promote products derived from this software . . . . . .

Você também pode usar sed para excluir texto da saída.

Excluindo texto

Você pode executar a exclusão de texto onde anteriormente estava especificando a impressão de texto alterando o comando p para o comando d.

Nesse caso, você não precisa mais do comando -n porque sed imprimirá tudo o que não for excluído. Isso ajudará você a ver o que está acontecendo.

Modifique o último comando da seção anterior para torná-lo

  1. sed '1~2d' BSD

O resultado é que você vê cada linha que não recebeu da última vez:

Output
All rights reserved. Redistribution and use in source and binary forms, with or without are met: notice, this list of conditions and the following disclaimer. notice, this list of conditions and the following disclaimer in the 3. Neither the name of the University nor the names of its contributors without specific prior written permission. . . . . . .

É importante observar aqui que nosso arquivo de origem não está sendo afetado. Ainda está intacto. As edições são enviadas para a nossa tela.

Se quisermos salvar nossas edições, podemos redirecionar a saída padrão para um arquivo como este:

  1. sed '1~2d' BSD > everyother.txt

Agora abra o arquivo com cat:

  1. cat everyother.txt

Você vê a mesma saída que viu na tela anteriormente:

Output
All rights reserved. Redistribution and use in source and binary forms, with or without are met: notice, this list of conditions and the following disclaimer. notice, this list of conditions and the following disclaimer in the 3. Neither the name of the University nor the names of its contributors without specific prior written permission. . . . . . .

O comando sed não edita o arquivo de origem por padrão, mas você pode alterar esse comportamento passando a opção -i, que significa \realizar edições no local. Isso alterará o arquivo de origem.

Aviso: Usar a opção -i irá sobrescrever o arquivo original, então você deve usar isso com cuidado. Execute as operações sem a opção -i primeiro e depois execute o comando novamente com -i assim que tiver o que deseja, crie um backup do arquivo original ou redirecione o saída para um arquivo. É muito fácil alterar acidentalmente o arquivo original com a opção -i.

Vamos tentar editando o arquivo everyother.txt que você acabou de criar, no local. Vamos reduzir ainda mais o arquivo excluindo todas as outras linhas

  1. sed -i '1~2d' everyother.txt

Se você usar cat para exibir o arquivo com cat everyother.txt, verá que o arquivo foi editado.

A opção -i pode ser perigosa. Felizmente, sed permite criar um arquivo de backup antes da edição.

Para criar um arquivo de backup antes da edição, adicione a extensão de backup diretamente após a opção \-i:

  1. sed -i.bak '1~2d' everyother.txt

Isso cria um arquivo de backup com a extensão .bak e, em seguida, edita o arquivo original no local.

Em seguida, você verá como usar sed para realizar operações de pesquisa e substituição.

Texto Substituto

Talvez o uso mais conhecido para sed seja a substituição de texto. sed pode procurar por padrões de texto usando expressões regulares e, em seguida, substituir o texto encontrado por outra coisa.

Você pode aprender mais sobre expressões regulares seguindo o artigo Usando expressões regulares do Grep para pesquisar padrões de texto no Linux.

Em sua forma mais básica, você pode alterar uma palavra para outra usando a seguinte sintaxe:

's/old_word/new_word/'

O s é o comando substituto. As três barras (/) são usadas para separar os diferentes campos de texto. Você pode usar outros caracteres para delimitar os campos se for mais útil.

Por exemplo, se você estiver tentando alterar o nome de um site, usar outro delimitador seria útil, pois os URLs contêm barras.

Execute o seguinte comando para imprimir uma URL com echo e modifique-a com sed, usando o caractere sublinhado (_) como delimitador:

  1. echo "http://www.example.com/index.html" | sed 's_com/index_org/home_'

Isso substitui com/index por org/home. A saída mostra o URL modificado:

Output
http://www.example.org/home.html

Não esqueça o delimitador final, ou sed irá reclamar. Se você executou este comando:

  1. echo "http://www.example.com/index.html" | sed 's_com/index_org/home'

Você veria esta saída:

Output
sed: -e expression #1, char 20: unterminated `s' command

Vamos criar um novo arquivo para praticar algumas substituições. Execute o seguinte comando para criar um novo arquivo de texto chamado song.txt:

  1. echo "this is the song that never ends
  2. yes, it goes on and on, my friend
  3. some people started singing it
  4. not knowing what it was
  5. and they'll continue singing it forever
  6. just because..." > song.txt

Agora vamos substituir a expressão on por forward. Use o seguinte comando:

  1. sed 's/on/forward/' song.txt

A saída se parece com isto:

Output
this is the sforwardg that never ends yes, it goes forward and on, my friend some people started singing it not knowing what it was and they'll cforwardtinue singing it forever just because...

Você pode ver algumas coisas notáveis aqui. Primeiro, é que sed substituiu padrões, não palavras. O on dentro de song é alterado para forward.

A outra coisa a notar é que na linha 2, o segundo on não foi alterado para forward.

Isso ocorre porque, por padrão, o comando s opera na primeira correspondência em uma linha e, em seguida, move-se para a próxima linha. Para fazer com que sed substitua todas as instâncias de on em vez de apenas a primeira em cada linha, você deve passar um sinalizador opcional para o comando substituto.

Forneça o sinalizador g para o comando substituto, colocando-o após o conjunto de substituição:

  1. sed 's/on/forward/g' song.txt

Você verá esta saída:

Output
this is the sforwardg that never ends yes, it goes forward and forward, my friend some people started singing it not knowing what it was and they'll cforwardtinue singing it forever just because...

Agora, o comando substituto altera todas as instâncias.

Se você somente quiser mudar a segunda instância de \on que o sed encontra em cada linha, então você deve usar o número 2 ao invés do g:

  1. sed 's/on/forward/2' song.txt

Desta vez, as outras linhas permanecem inalteradas, pois não possuem uma segunda ocorrência:

Output
this is the song that never ends yes, it goes on and forward, my friend some people started singing it not knowing what it was and they'll continue singing it forever just because...

Se você quiser apenas ver quais linhas foram substituídas, use a opção -n novamente para suprimir a impressão automática.

Você pode então passar a opção p para o comando de substituição para imprimir as linhas onde ocorreu a substituição.

  1. sed -n 's/on/forward/2p' song.txt

A linha que mudou imprime na tela:

Output
yes, it goes on and forward, my friend

Como você pode ver, você pode combinar os sinalizadores no final do comando.

Se você deseja que o processo de pesquisa ignore maiúsculas e minúsculas, pode passar o sinalizador \i.

  1. sed 's/SINGING/saying/i' song.txt

Aqui está a saída que você verá:

Output
this is the song that never ends yes, it goes on and on, my friend some people started saying it not knowing what it was and they'll continue saying it forever just because...

Substituindo e fazendo referência ao texto correspondente

Se quiser localizar padrões mais complexos com expressões regulares, você tem vários métodos diferentes para referenciar o padrão correspondente no texto de substituição.

Por exemplo, para corresponder desde o início da linha até at, use o seguinte comando:

  1. sed 's/^.*at/REPLACED/' song.txt

Você verá esta saída:

Output
REPLACED never ends yes, it goes on and on, my friend some people started singing it REPLACED it was and they'll continue singing it forever just because...

Você pode ver que a expressão curinga corresponde desde o início da linha até a última instância de at.

Como você não sabe a frase exata que corresponderá à string de pesquisa, poderá usar o caractere & para representar o texto correspondente na string de substituição.

Vamos colocar parênteses ao redor do texto correspondente:

  1. sed 's/^.*at/(&)/' song.txt

Você verá esta saída:

Output
(this is the song that) never ends yes, it goes on and on, my friend some people started singing it (not knowing what) it was and they'll continue singing it forever just because...

Uma maneira mais flexível de fazer referência ao texto correspondente é usar parênteses de escape para agrupar seções do texto correspondente.

Cada grupo de texto de pesquisa marcado com parênteses pode ser referenciado por um número de referência com escape. Por exemplo, o primeiro grupo de parênteses pode ser referenciado com , o segundo com e assim por diante.

Neste exemplo, trocaremos as duas primeiras palavras de cada linha:

  1. sed 's/\([a-zA-Z0-9][a-zA-Z0-9]*\) \([a-zA-Z0-9][a-zA-Z0-9]*\)/\2 \1/' song.txt

Você verá esta saída:

Output
is this the song that never ends yes, goes it on and on, my friend people some started singing it knowing not what it was they and'll continue singing it forever because just...

Como você pode ver, os resultados não são perfeitos. Por exemplo, a segunda linha pula a primeira palavra porque contém um caractere não listado em nosso conjunto de caracteres. Da mesma forma, tratou theyll como duas palavras na quinta linha.

Vamos melhorar a expressão regular para ser mais preciso:

  1. sed 's/\([^ ][^ ]*\) \([^ ][^ ]*\)/\2 \1/' song.txt

Você verá esta saída:

Output
is this the song that never ends it yes, goes on and on, my friend people some started singing it knowing not what it was they'll and continue singing it forever because... just

Isso é muito melhor do que da última vez. Isso agrupa a pontuação com a palavra associada.

Observe como repetimos a expressão dentro dos parênteses (uma vez sem o caractere * e outra vez com ele). Isso ocorre porque o caractere * corresponde zero ou mais vezes ao conjunto de caracteres que vem antes dele. Isso significa que a correspondência com o curinga seria considerada uma correspondência mesmo que o padrão não fosse encontrado.

Para garantir que sed encontre o texto pelo menos uma vez, você deve combiná-lo uma vez sem o curinga antes de empregar o curinga.

Conclusão

Neste tutorial, você explorou o comando sed. Você imprimiu linhas específicas do arquivo, pesquisou texto, excluiu linhas, substituiu o arquivo original e usou expressões regulares para substituir o texto. Você já deve ser capaz de ver como pode transformar rapidamente um documento de texto usando comandos sed construídos corretamente.

No próximo artigo desta série, você explorará alguns recursos mais avançados.

Artigos relacionados: