Как tr переводит одно слово в другое?

9

У меня есть файл ma.txt и он содержит результат ls -l ; когда я запускаю команду tr ( tr "nik-pc" "root" ), я получаю этот вывод:

[email protected]:~$ 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

[email protected]:~$ 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

В первой строке он заменил «nik» на «слишком», и написание «Desktop» стало «Desottt».

Почему это? Что такое логика?

    
задан Manish Bharti 17.03.2016 в 14:31
источник

2 ответа

16

tr переводит строку по типу. Он ищет буквы из первого набора и заменяет их теми, которые образуют второй набор.

У вас был nik-pc как первый набор. tr расширяет часть k-p по отношению ко всем буквам в диапазоне от «k» до «p», поэтому набор равен niklmnopc .

Ваш второй набор был root .

Теперь tr выполняет поиск всех вхождений первого символа в (оцененном) первом наборе и заменяет их первым символом второго набора. Когда в наборе 2 больше нет символа, он просто повторяет свой последний символ. См. Таблицу ниже:

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

Итак, теперь понятно, почему, например, «Рабочий стол» становится «Desottt». Поведение полностью верно и предназначено таким образом.

То, что вы ищете, может быть достигнуто с помощью sed :

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

Синтаксис таков:

sed 's/SEARCH_PATTERN/REPLACE_STRING/FLAGS' INPUT_FILE

Итак, мы разрешаем ему искать шаблон «nik-pc» и заменять весь матч «root». Нам нужно добавить флаг «g», чтобы включить глобальную замену. Без этого он заменит только каждое первое соответствие на строку.

    
ответ дан Byte Commander 17.03.2016 в 15:07
источник
18

tr предназначен для перевода символов, а не для полных слов. Он может переводить множества. В вашем примере у вас есть «nik-pc» в качестве первых символов коллекции, а «root» - другой. Фактически, k-p - это диапазон, поэтому он включает все символы от k до p. Он будет соответствовать символам один за другим, поэтому n будет переводить на r, i в o, k на o, и все остальное за четвертым символом будет t. Вот почему у вас есть «Рабочий стол», переведенный на «Desottt»

Вы можете увидеть это более четко в этом примере:

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

Здесь вы можете увидеть, что tr установлено 1 имеет D в позиции 4. Но у 2-го не будет позиции 4, поэтому он будет использовать последнюю позицию, которую должен выполнить перевод 2.

То, что вы делаете, означает перевод одного слова в другое. Вы хотите использовать более продвинутый инструмент, например, sed или awk .

Например,

$ ls -l /etc/passwd | awk '{gsub(/root/,"TEST");print}'        
-rw-r--r-- 1 TEST TEST 2575 Feb 29 12:30 /etc/passwd
    
ответ дан Sergiy Kolodyazhnyy 17.03.2016 в 14:51