Intereting Posts
Арифметическая синтаксическая ошибка с числовой переменной Ни одна из программ Linux не работает, кроме 'cd' Как очистить оперативную память, которая используется в качестве кэш-памяти? Как установить цветовые схемы для Kate, работающие на GNOME scdaemon / gpg не работает Настройте сетевой интерфейс для отправки фреймов с форматом 802.3 на freebsd почему такие программы, как su, доступ к / etc / shadow Поврежденный файл gz Bash больше не работает Каталог изменений Уменьшение потери пакетов при ограничении скорости tc Чтение номеров из файла управления и извлечение совпадающих номеров строк из файла данных Как разбить файл и вывести его из команды? Полное определение ключа XKB Никакая звуковая карта не обнаружена в Linux Mint 18.1 (и Windows 10) после установки с двойной загрузкой на ноутбуке Asus UX410UQ (Kabylake) Как я могу сгладить два шаблона из одного файла и направить строки на разные выходные файлы в зависимости от того, какая совпадение соответствует?

tr не заменяет апостроф

Я хочу преобразовать все апострофы в этот файл в X :

 Bob's book Bob's book Bob′s book # (Might look the same but actually different) 

Первый апостроф заменяется, как и ожидалось:

 $ cat file | tr "'" "X" BobXs book Bob's book Bob′s book 

Но два других вида апострофа: происходят странные вещи:

 $ cat file | tr "'" "X" Bob's book BobXXXs book BobXX s book $ cat file | tr "′" "X" Bob's book BobXX s book BobXXXs book 

Как заставить его работать?

tr работает в единицах байтов, что означает, что он не работает должным образом для многобайтовых кодировок, таких как UTF-8. Единственные решения, которые я знаю, – это найти версию tr которая поддерживает Unicode, или переключиться на sed или какой-нибудь другой инструмент, который может выполнять замену строк.

Для меня tr работает как для файлов ascii, так и для utf-8, так как ваша ОС настроена на работу с кодовой страницей utf-8.

Вот мой пример №1 (Solaris 11):

 $ locale LANG=en_US.UTF-8 LC_CTYPE="en_US.UTF-8" LC_NUMERIC="en_US.UTF-8" LC_TIME="en_US.UTF-8" LC_COLLATE="en_US.UTF-8" LC_MONETARY="en_US.UTF-8" LC_MESSAGES="en_US.UTF-8" LC_ALL= 

Как вы можете видеть, ОС настроена на работу с utf-8. Я создал оба файла в кодировке utf-8:

 $ cat file Bob's Bob′s Bob's $ cat apos '′' 

Затем я получил ожидаемые результаты, заменив все apos следующим образом:

 $ cat file | tr "$(cat apos)" "xxx" Bobxs Bobxs Bobxs 

Вот мой пример № 2 (Solaris 10):

 $ locale LANG= LC_CTYPE="C" LC_NUMERIC="C" LC_TIME="C" LC_COLLATE="C" LC_MONETARY="C" LC_MESSAGES="C" LC_ALL= 

Здесь вы можете увидеть, что эта ОС настроена на работу с простым ASCII, а не с utf-8, поэтому вы можете ожидать проблемы с обработкой файлов utf-8 с многобайтовыми символами с помощью tr. Но есть обходной путь. Поскольку команда tr позволяет вводить восьмеричное представление символа, вы можете заменить все байты указанного символа, используя восьмеричное представление.

В вашем случае у вас есть:

 char hex octal ' E2 80 99 \342\200\231 ′ E2 80 B2 \342\200\262 ' 27 \47 

Firts и second apos представлены тремя байтами. Третий – стандартный ascii (один байт).

Поэтому, если вы хотите заменить первые апои, вы можете использовать:

 $ cat file | tr "\342\200\231" "\0\0x" Bobxs Bob▒s Bob's 

Во-вторых:

 $ cat file | tr "\342\200\262" "\0\0x" Bob▒s Bobxs Bob's 

В третьих:

 $ cat file | tr "\47" "x" Bob's Bob′s Bobxs 

Чтобы заменить все за один выстрел, вы можете использовать:

 $ cat file | tr "\342\200\231\262\47" "\0\0xxx" Bobxs Bobxs Bobxs 

Конечно, это не так долго, это заменит все вхождения байта \ 342, \ 200, \ 231, \ 262 в файл, поэтому другие многобайтовые символы, содержащие эти байты, будут сломаны. Но если ваш файл не содержит других многобайтовых символов, он будет работать.