Como tr traduz uma palavra para outra?

9

Eu tenho um arquivo ma.txte ele contém a saída de ls -l; quando executo o trcomando ( tr "nik-pc" "root"), recebo esta saída:

nik-pc@nik:~$ cat ma.txt 
total 52
drwxr-xr-x 2 nik-pc nik-pc 4096 Mar 11 11:33 Desktop
lrwxrwxrwx 1 nik-pc nik-pc    2 Mar  8 22:54 di -> hd
drwxr-xr-x 3 nik-pc nik-pc 4096 Mar 13 13:28 Documents
drwxr-xr-x 7 nik-pc nik-pc 4096 Mar 14 18:21 Downloads
drwxr-xr-x 2 nik-pc nik-pc 4096 Mar 11 09:39 dwhelper
-rw-r--r-- 1 nik-pc nik-pc 2134 Mar 13 17:40 hd
-rw-r--r-- 1 nik-pc nik-pc    3 Mar 13 15:34 m
-rw-r--r-- 1 nik-pc nik-pc    0 Mar 17 19:48 ma.txt
drwxr-xr-x 3 nik-pc nik-pc 4096 Mar 13 14:58 Music
drwxr-xr-x 2 nik-pc nik-pc 4096 Mar  5 12:30 Pictures
drwxr-xr-x 2 nik-pc nik-pc 4096 Mar  5 11:44 Public
drwxr-xr-x 2 nik-pc nik-pc 4096 Mar 13 15:58 sd
drwxr-xr-x 2 nik-pc nik-pc 4096 Mar  5 11:44 Templates
drwxr-xr-x 2 nik-pc nik-pc 4096 Mar  5 11:44 Videos
drwxr-xr-x 2 nik-pc nik-pc 4096 Mar 11 11:33 xdm-helper

nik-pc@nik:~$ tr "nik-pc" "root" < ma.txt 
tttat 52
drwxr-xr-x 2 too-tt too-tt 4096 Mar 11 11:33 Desottt
trwxrwxrwx 1 too-tt too-tt    2 Mar  8 22:54 do -> hd
drwxr-xr-x 3 too-tt too-tt 4096 Mar 13 13:28 Dttutetts
drwxr-xr-x 7 too-tt too-tt 4096 Mar 14 18:21 Dtwtttads
drwxr-xr-x 2 too-tt too-tt 4096 Mar 11 09:39 dwhetter
-rw-r--r-- 1 too-tt too-tt 2134 Mar 13 17:40 hd
-rw-r--r-- 1 too-tt too-tt    3 Mar 13 15:34 t
-rw-r--r-- 1 too-tt too-tt    0 Mar 17 19:48 ta.txt
drwxr-xr-x 3 too-tt too-tt 4096 Mar 13 14:58 Musot
drwxr-xr-x 2 too-tt too-tt 4096 Mar  5 12:30 Pottures
drwxr-xr-x 2 too-tt too-tt 4096 Mar  5 11:44 Pubtot
drwxr-xr-x 2 too-tt too-tt 4096 Mar 13 15:58 sd
drwxr-xr-x 2 too-tt too-tt 4096 Mar  5 11:44 Tetttates
drwxr-xr-x 2 too-tt too-tt 4096 Mar  5 11:44 Vodets
drwxr-xr-x 2 too-tt too-tt 4096 Mar 11 11:33 xdt-hetter

Na linha um, substituiu "nik" por "too" e a grafia de "Desktop" se tornou "Desottt".

Por que é isso? Qual é a lógica por trás disso?

Manish Bharti
fonte
3
info coreutils 'tr invocation'informa detalhadamente o que trfaz.
Nephente 17/03/16
4
O que você está tentando fazer a propósito? O comando foi exatamente o que você disse para fazer, mas eu acho que você realmente deseja substituir nik-pccom root?
kos
3
O primeiro passo é sempre verificar a página de manual do comando.
Mostafa Ahangarha 17/03/16
11
@ DavidD: Note que ntambém está no k-pintervalo. O resultado de um caractere aparecendo mais de uma vez no primeiro conjunto não é especificado pelo POSIX.
hmakholm deixou Monica em 17/03/16
11
Eu acho que o que você realmente precisa, é o sedcomando ... ls -l | sed 's/nik-pc/root/'faria o que você quiser. tré para converter caracteres únicos - por exemplo. linhas minúsculas para maiúsculas, ou deslocamento de linha no estilo dos (\ r) para estilo Unix (\ n), ou algo como substituir todas as barras invertidas (Windows) por barras. Também pode excluir caracteres "indesejados", por exemplo. todos os números ou todas as letras maiúsculas.
Baard Kopperud 17/03/16

Respostas:

16

trtraduz uma string em caracteres. Ele pesquisa as letras do primeiro conjunto e as substitui por aquelas do segundo conjunto.

Você teve nik-pccomo primeiro set. trexpande a k-pparte em que para todas as letras no intervalo de "k" a "p", portanto o conjunto é igual a niklmnopc.

Seu segundo set foi root.

O que tragora faz é procurar todas as ocorrências do primeiro caractere no primeiro conjunto (avaliado) e substituí-las pelo primeiro caractere do segundo conjunto. Quando não há mais caracteres no conjunto 2, ele simplesmente repete o último caractere. Veja a tabela abaixo:

n --> r
i --> o
k --> o
l --> t
m --> t
n --> t
o --> t
p --> t
c --> t

Então agora está claro por que, por exemplo, "Desktop" se torna "Desottt". O comportamento é totalmente correto e é planejado dessa maneira.


Em vez disso, o que você está procurando pode ser alcançado usando sed:

sed 's/nik-pc/root/g' ma.txt

A sintaxe é esta:

sed 's/SEARCH_PATTERN/REPLACE_STRING/FLAGS' INPUT_FILE

Então, deixamos que ele procure o padrão "nik-pc" e substitua a correspondência inteira por "root". Precisamos adicionar o sinalizador "g" para ativar a substituição global. Sem isso, apenas substituiria cada primeira partida por linha.

Byte Commander
fonte
Essa mesa com setas torna a explicação ainda mais clara, eu gosto disso. + 1 ed. Um usuário provavelmente poderia fazer algo parecido com #printf "A\nB\nC\n" | tr 'ABC' '12'
Sergiy Kolodyazhnyy 17/03
18

tré para traduzir caracteres, não para palavras completas. Pode traduzir conjuntos. No seu exemplo, você tem "nik-pc" como primeiros caracteres da coleção, e "root" é outro. De fato, k-pé um intervalo, portanto inclui todos os caracteres de k a p. Ele corresponderá aos caracteres um por um, então n será traduzido para r, i para o, k para o, e o que for além do quarto caractere será t. É por isso que você traduz "Desktop" para "Desottt"

Você pode vê-lo mais claramente neste exemplo:

$ echo "ABCDEF" | tr "ABCDEF"  "12"                            
122222

Aqui você pode ver o tr conjunto 1 com D na posição 4. Mas o conjunto 2 não possui a posição 4, portanto, ele usará a última posição que o conjunto 2 deve traduzir.

O que você está fazendo é traduzir uma palavra para outra. O que você quer fazer é usar uma ferramenta mais avançada como sedou awk.

Por exemplo,

$ ls -l /etc/passwd | awk '{gsub(/root/,"TEST");print}'        
-rw-r--r-- 1 TEST TEST 2575 Feb 29 12:30 /etc/passwd
Sergiy Kolodyazhnyy
fonte
6
OR sed s / nik-pc / root / g ma.txt> ma2.txt
Bruni
11
Você foi muito mais rápido que eu @Serg ...: P
Byte Commander
2
@ByteCommander Posso ter vencido em velocidade, mas acho que sua resposta ganha em qualidade #
Sergiy Kolodyazhnyy