Как преобразовать текстовые файлы UTF-8 в верхний регистр в bash?

10

У меня есть несколько UTF-8 .txt файлов, которые я хотел бы преобразовать в верхний регистр. Если бы это был просто ASCII, я мог бы использовать:

tr [:lower:] [:upper:]

Но так как я работаю с диакритическими знаками и прочим, это, похоже, не работает. Я думаю, это может сработать, если я установлю соответствующую локаль, но мне нужно, чтобы этот скрипт был переносимым.

VPeric
источник

Ответы:

14

Все:

tr '[:lower:]' '[:upper:]'

(не забудьте кавычки, в противном случае , что не будет работать , если есть файл с именем :, l... или rв текущем каталоге) или:

awk '{print toupper($0)}'

или:

dd conv=ucase

предназначены для преобразования символов в верхний регистр в соответствии с правилами, определенными в текущей локали. Однако даже в тех случаях, когда локали используют UTF-8 в качестве набора символов и четко определяют преобразование из строчных в прописные, по крайней мере, GNU dd, GNU trи mawk(по умолчанию awkв Ubuntu, например) не следуют им. Кроме того, не существует стандартного способа указать локали, отличные от Cили POSIX, поэтому, если вы хотите преобразовать файлы UTF-8 в верхний регистр переносимым независимо от текущей локали, вам не повезло с помощью стандартной инструментальной панели.

Как часто, для мобильности, ваша лучшая ставка может быть perl:

$ echo lľsšcčtťzž | PERLIO=:utf8 perl -pe '$_=uc'
LĽSŠCČTŤZŽ

Теперь вам нужно остерегаться того, что не все согласны с тем, что является заглавной версией конкретного символа.

Например, в турецких языках прописными буквами iне является I, но İ( <U0130>). Вот с помощью инструмента семейной реликвии trвместо GNU tr:

$ echo ií | LC_ALL=C.UTF-8 tr '[:lower:]' '[:upper:]'
IÍ
$ echo ií | LC_ALL=tr_TR.UTF-8 tr '[:lower:]' '[:upper:]'
İÍ

В моей системе perlпреобразование в верхнюю часть определено в /usr/share/perl/5.14/unicore/To/Upper.pl, и я считаю, что оно ведет себя по-разному на нескольких символах, например, из GNU libc toupper()в C.UTF8локали, perlчто является более точным. Например, perlправильно преобразует ɀ в Ɀ , а GNU libc (2.17) - нет.

Стефан Шазелас
источник
Для чего стоит, я работаю с чешскими буквами (и пример, который вы использовали на самом деле словацкий), где все прописные буквы четко определены, но набор локалей, вероятно, будет C, а не чешский, так что это проблема. Perl уже используется в этом наборе инструментов, поэтому добавление еще одного использования не так уж плохо. Спасибо за подробное объяснение, кстати!
VPeric
3

Я думаю, что вы можете сделать это с awkего toupperфункцией.

Например

Не работает с GNU tr:

$ echo lľsšcčtťzž | tr '[:lower:]' '[:upper:]'
LľSšCčTťZž

Работает с GNU awk:

$ echo lľsšcčtťzž | awk '{ print toupper($0) }'
LĽSŠCČTŤZŽ
SLM
источник
@StephaneChazelas - спасибо, я изменил неудачный пример.
slm
Это зависит от текущей локали и от реализации trили awk. Например, большинство из них trбудет правильно преобразовывать символы, когда в локали UTF8, в соответствии с текущей локалью, GNU trэтого не делает. mawkне делает.
Стефан Шазелас
1
На самом деле, во FreeBSD (9.1) все наоборот. Это работает с tr, но не сawk
Стефан Шазелас
@StephaneChazelas - я не так разбираюсь в отклонениях 8-). Кто-то просто проголосовал, интересно, почему?
SLM
2

Это работает с OS X, trно не с GNU tr:

tr '[:lower:]' '[:upper:]'

Это работает с, gawkно не с mawkили nawk(который находится /usr/bin/awkв OS X):

awk '{print toupper($0)}'

Другой вариант - использовать GNU sed:

sed 's/./\u&/g'

В Bash 4.0 и более поздних версиях вы также можете использовать ^^расширение параметра:

while IFS= read -r l;do printf %s\\n "${l^^}";done
nisetama
источник