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

9

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

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

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

Почему это? Какая логика стоит за этим?

Маниш Бхарти
источник
3
info coreutils 'tr invocation'подробно рассказывает, что trделает.
Nephente
4
Кстати, что вы пытаетесь сделать? Команда сделала именно то , что вы сказали это сделать, но я предполагаю , что вы на самом деле хотите , чтобы заменить nik-pcс root?
Кос
3
Первый шаг - всегда проверять справочную страницу команды.
Мостафа Ахангарха
1
@DavidZ: обратите внимание, что nтакже в k-pдиапазоне. POSIX не указывает, что результат появления символа в первом наборе более одного раза.
Хмакхольм покинул Монику
1
Я думаю, что вам действительно нужно, это sedкоманда ... ls -l | sed 's/nik-pc/root/'будет делать то, что вы хотите. trдля преобразования отдельных символов - например. строчные буквы в верхний регистр, или смещение строк в стиле dos (\ r) в стиле Unix (\ n), или что-то вроде замены всех обратных косых черт (Windows) косыми чертами. Он также может удалять «нежелательные» символы, например. все цифры или все заглавные буквы.
Баард Копперуд

Ответы:

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
источник
Эта таблица со стрелками делает объяснение еще яснее, мне это нравится. + 1-е изд. Пользователь может, вероятно, сделать что-то подобное сprintf "A\nB\nC\n" | tr 'ABC' '12'
Сергей Колодяжный
18

trдля перевода символов, а не для полных слов. Он может переводить наборы. В вашем примере у вас есть «nik-pc» в качестве первого набора символов, а «root» - другой. Фактически k-pэто диапазон, поэтому он включает в себя все символы от k до p. Он будет соответствовать символам один за другим, поэтому n будет переводиться в r, i в o, k в o, и все, что находится за пределами 4-го символа, будет 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
Сергей Колодяжный
источник
6
ИЛИ sed s / nik-pc / root / g ma.txt> ma2.txt
Бруни
1
Ты был намного быстрее меня @Serg ...: P
Byte Commander
2
@ByteCommander Возможно, я выиграл в скорости, но я думаю, что ваш ответ выигрывает по качеству
Сергей Колодяжный