Como o tr traduz uma palavra para outra?

9

Eu tenho um arquivo ma.txt e ele contém a saída de ls -l ; quando eu executo o comando tr ( tr "nik-pc" "root" ) eu 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 ortografia de "Desktop" tornou-se "Desottt".

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

    
por Manish Bharti 17.03.2016 / 15:31

2 respostas

16

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

Você tinha nik-pc como primeiro conjunto. tr expande a parte k-p para todas as letras no intervalo de "k" para "p", então o conjunto é igual a niklmnopc .

Seu segundo conjunto foi root .

O que o tr faz agora é pesquisar 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 caractere no conjunto 2, ele simplesmente repete seu ú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 o porquê "Desktop" torna-se "Desottt". O comportamento é totalmente correto e destinado desta forma.

O que você procura pode ser obtido 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 pesquisar pelo padrão "nik-pc" e substituímos a correspondência inteira por "root". Precisamos adicionar o sinalizador "g" para ativar a substituição global. Sem isso, apenas substituiria cada primeiro jogo por linha.

    
por Byte Commander 17.03.2016 / 16:07
18

tr é para traduzir caracteres, não para palavras completas. Pode traduzir conjuntos. No seu exemplo você tem "nik-pc" como primeiro caractere de coleção, e "root" é outro. De fato, k-p é um intervalo, então inclui todos os caracteres de k a p. Ele irá combinar chars um por um, então n irá traduzir para r, i para o, k para o, e qualquer outra coisa além do 4o char será t. É por isso que você tem "Desktop" traduzido como "Desottt"

Você pode ver isso mais claramente neste exemplo:

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

Aqui você pode ver tr set 1 ter D na posição 4. Mas o conjunto 2 não tem posição 4, então ele usará o último conjunto de posições 2 para traduzir.

O que você está fazendo é traduzir uma palavra para outra. O que você quer fazer é usar uma ferramenta mais avançada, como sed ou 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
    
por Sergiy Kolodyazhnyy 17.03.2016 / 15:51