Posso usar 'sed' para traduzir caracteres como 'tr'?

12

Eu gostaria de substituir um conjunto de caracteres com caracteres correspondentes de outro conjunto, algo assim:

original set: ots
"target" set: u.x

foobartest → fuubar.ex.

Traduções / transliterações como essa são a especialidade do comando tr :

$ echo 'foobartest' | tr 'ots' 'u.x'
fuubar.ex.

Infelizmente tr não suporta a alteração de arquivos no local como sed .
Eu gostaria de usar sed , então não preciso reinventar a roda dos arquivos temporários de malabarismo.

    
por n.st 13.09.2017 / 18:27

3 respostas

22

sed tem o comando y que funciona como tr :

$ echo 'foobartest' | sed 'y/ots/u.x/'
fuubar.ex.

O comando y faz parte da especificação POSIX sed , por isso deve trabalhar em praticamente qualquer plataforma.

E como é sed , você pode substituir um arquivo por sua versão editada, poupando-lhe o incômodo negócio de arquivos temporários (desde que sua implementação de sed suporte a opção -i , que não é especificada por POSIX ):

$ sed -i 'y/ots/u.x/' some-file.txt
    
por 13.09.2017 / 18:27
7

Se, como no seu caso, você estiver transliterando caracteres sem alterar seu tamanho (de qualquer forma, algumas implementações como o GNU tr suportam apenas caracteres de byte único), você pode fazer:

tr 'ots' 'u.x' < file 1<> file

Ou seja, tem tr sobrescrever o arquivo sobre si mesmo.

Isso é melhor que sed -i em várias contas:

  • não precisa de espaço extra em disco (exceto em alguns casos esparsos, casos especiais de cópia na gravação)
  • preserva números de inode, propriedade, permissões, ACLs ...
  • funciona bem com links simbólicos, não quebra links físicos
  • não deixa arquivos temporários mentindo quando são mortos.

Uma desvantagem é que, se for interrompido, o arquivo terminará sendo parcialmente traduzido (neste caso, você poderá executá-lo novamente para finalizá-lo). Algumas implementações de sed lidariam com isso corretamente, certificando-se de que o arquivo original permaneça inalterado, a menos que o comando seja bem-sucedido.

    
por 13.09.2017 / 18:38
3

Como outra alternativa, se o seu problema principal for a falta de suporte para alterar arquivos no local, talvez você esteja interessado na ferramenta sponge do pacote moreutils :

tr 'ots' 'u.x' < file | sponge file

gravará em file , mas só abrirá file para escrita quando a entrada estiver completa. Na página de manual :

sponge reads standard input and writes it out to the specified file. Unlike a shell redirect, sponge soaks up all its input before opening the output file. This allows constructing pipelines that read from and write to the same file.

A menos que você tenha arquivos realmente grandes que não possam ser mantidos na memória, sponge pode funcionar para você.

    
por 13.09.2017 / 21:26

Tags