Gostaria de substituir um conjunto de caracteres pelos caracteres correspondentes de outro conjunto, algo como isto:
original set: ots
"target" set: u.x
foobartest → fuubar.ex.
Traduções / transliterações como esta são a especialidade do tr
comando:
$ echo 'foobartest' | tr 'ots' 'u.x'
fuubar.ex.
Infelizmente tr
, não suporta a alteração de arquivos no local, como o sed
faz.
Gostaria de usar sed
para não precisar reinventar a roda de arquivos temporários de malabarismo.
tr
(corretamente) ignora a recursão nos conjuntos de substituição:echo 'abc' | tr ab bx
→bxc
. Uma solução primitiva pode ocultar issoxxc
porque reaplicará a tradução a caracteres que já foram traduzidos.sed
contrário ao GNUtr
transliteramos caracteres multi-byte)Respostas:
sed
tem oy
comando que funciona exatamente comotr
:O
y
comando faz parte da especificação POSIXsed
, portanto, deve funcionar em praticamente qualquer plataforma.E como é
sed
, você pode substituir um arquivo por sua versão editada, poupando-lhe os incômodos negócios de arquivos temporários (desde que sua implementaçãosed
ofereça suporte à-i
opção, que não é especificada pelo POSIX):fonte
sed
não significa que as outras funções também sejam. ;) A lista de discussão do Vim tem um tópico sobre como encontrar umy/abc/def/
equivalente; a melhor opção parece ser:%call setline(".", tr(getline("."),"abc","def"))
.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:Ou seja,
tr
substitui o arquivo por si próprio.Isso é melhor do que
sed -i
em várias contas:Uma desvantagem é que, se for interrompido, o arquivo acabará sendo parcialmente traduzido (nesse caso, você pode executá-lo novamente para finalizá-lo). Algumas
sed
implementações lidariam com isso corretamente, garantindo que o arquivo original permanecesse inalterado, a menos que o comando tenha êxito.fonte
echo 'abc' | tr ab bx
.tr
e em nosso ambiente PXE com muitos links simbólicos,sed -i
era uma espera estragada acontecer…: /iconv -t cp437
parece mais apropriado para isso.iconv
quebra quando o arquivo de entrada já contém bytes codificados em cp437 ou uma mistura de várias codificações. Portanto, embora seja preferível no caso geral, é mais robusto fazer substituições manuais nesse caso.Como outra alternativa, se o seu principal problema for a falta de suporte para a alteração de arquivos no local, você pode estar interessado na
sponge
ferramenta do pacote moreutils :gravará em
file
, mas só será abertofile
para gravação quando a entrada estiver concluída. Na página de manual :A menos que você tenha arquivos muito grandes que não possam ser armazenados na memória, eles
sponge
podem funcionar para você.fonte
sponge
é que ele ainda substituifile
setr
falhar (por exemplo, se você tinha gravação, mas não acesso de leiturafile
)cat file >; file
operador do ksh93 que grava a saída em um arquivo temporário que é renomeado para o destino somente se o comando for bem-sucedido (massed -i
, por exemplo, isso cria um novo arquivo em vez de substituir o original).