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 é:
- 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:
- cd
- 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:
- cat << 'EOF' > BSD
- 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.
- 3. Neither the name of the University nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
- 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:
- sed '' BSD
Você verá a licença BSD exibida na tela:
OutputCopyright (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:
- cat BSD | sed ''
Você verá a saída do arquivo:
OutputCopyright (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:
- sed 'p' BSD
Você verá cada linha do arquivo BSD
impressa duas vezes:
OutputCopyright (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:
- sed -n 'p' BSD
OutputCopyright (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:
- sed -n '1p' BSD
A primeira linha imprime na tela:
OutputCopyright (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):
- sed -n '1,5p' BSD
Você verá esta saída:
OutputCopyright (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:
- 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:
- sed -n '1~2p' BSD
Aqui está a saída que você verá:
OutputCopyright (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
- sed '1~2d' BSD
O resultado é que você vê cada linha que não recebeu da última vez:
OutputAll 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:
- sed '1~2d' BSD > everyother.txt
Agora abra o arquivo com cat
:
- cat everyother.txt
Você vê a mesma saída que viu na tela anteriormente:
OutputAll 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
- 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:
- 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:
- 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:
Outputhttp://www.example.org/home.html
Não esqueça o delimitador final, ou sed
irá reclamar. Se você executou este comando:
- echo "http://www.example.com/index.html" | sed 's_com/index_org/home'
Você veria esta saída:
Outputsed: -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
:
- echo "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..." > song.txt
Agora vamos substituir a expressão on
por forward
. Use o seguinte comando:
- sed 's/on/forward/' song.txt
A saída se parece com isto:
Outputthis 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:
- sed 's/on/forward/g' song.txt
Você verá esta saída:
Outputthis 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
:
- sed 's/on/forward/2' song.txt
Desta vez, as outras linhas permanecem inalteradas, pois não possuem uma segunda ocorrência:
Outputthis 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.
- sed -n 's/on/forward/2p' song.txt
A linha que mudou imprime na tela:
Outputyes, 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.
- sed 's/SINGING/saying/i' song.txt
Aqui está a saída que você verá:
Outputthis 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:
- sed 's/^.*at/REPLACED/' song.txt
Você verá esta saída:
OutputREPLACED 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:
- 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:
- 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:
Outputis 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:
- sed 's/\([^ ][^ ]*\) \([^ ][^ ]*\)/\2 \1/' song.txt
Você verá esta saída:
Outputis 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.