Como converter arquivos UTF-8 txt para maiúsculas no bash?

10

Eu tenho alguns arquivos .txt UTF-8 que gostaria de converter para todas as maiúsculas. Se fosse apenas ASCII, eu poderia usar:

tr [:lower:] [:upper:]

Mas desde que eu estou trabalhando com diacríticos e outras coisas, isso não parece funcionar. Eu acho que pode funcionar se eu definir o local apropriado, mas preciso que esse script seja portátil.

VPeric
fonte

Respostas:

14

Tudo de:

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

(não se esqueça das citações, de outra forma que não vai funcionar se houver um arquivo chamado :, l... ou rno diretório atual) ou:

awk '{print toupper($0)}'

ou:

dd conv=ucase

destinam-se a converter caracteres em maiúsculas de acordo com as regras definidas no código do idioma atual. No entanto, mesmo onde as localidades usam UTF-8 como o conjunto de caracteres e definem claramente a conversão de minúsculas para maiúsculas, pelo menos GNU dd, GNU tre mawk(o padrão awkno Ubuntu, por exemplo) não as seguem. Além disso, não há uma maneira padrão de especificar códigos de idioma que não sejam Cou POSIX, portanto, se você deseja converter arquivos UTF-8 em maiúsculas, de maneira portável, independentemente do código de idioma atual, você não tem sorte com o guia de ferramentas padrão.

Com frequência, para portabilidade, sua melhor aposta pode ser perl:

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

Agora, você deve ter cuidado, pois nem todos concordam com a versão em maiúscula de um caractere específico.

Por exemplo, nas localidades turcas, as maiúsculas inão são I, mas İ( <U0130>). Aqui, com o baú trde ferramentas da herança em vez do GNU tr:

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

No meu sistema, a perlconversão para superior é definida em /usr/share/perl/5.14/unicore/To/Upper.pl, e acho que ela se comporta de maneira diferente em alguns caracteres da GNU libc toupper()na C.UTF8localidade, por exemplo, perlsendo mais precisa. Por exemplo, perlconverte corretamente ɀ para Ɀ , o GNU libc (2.17) não.

Stéphane Chazelas
fonte
Pelo que vale, estou trabalhando com letras tchecas (e o exemplo que você usou é na verdade eslovaco), onde todas as letras maiúsculas são claramente definidas, mas o conjunto de localidades provavelmente será C e não tcheco, por isso é um problema. O Perl já está sendo usado nesta cadeia de ferramentas, portanto, adicionar outro uso pode não ser tão ruim. Obrigado pela explicação detalhada, btw!
VPeric
3

Eu acho que você pode fazer isso com awke sua toupperfunção.

Por exemplo

Não funciona com o GNU tr:

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

Funciona com GNU awk:

$ echo lľsšcčtťzž | awk '{ print toupper($0) }'
LĽSŠCČTŤZŽ
slm
fonte
@StephaneChazelas - obrigado, mudei o exemplo que falhou.
slm
Isso depende da localidade atual e sobre a trou awkimplementação. Por exemplo, a maioria trconverterá caracteres corretamente quando em um local UTF8, de acordo com o local atual, o GNU trnão. mawknão.
Stéphane Chazelas
1
Na verdade, no FreeBSD (9.1), é o contrário. Funciona com tr, mas não comawk
Stéphane Chazelas
@StephaneChazelas - Eu não sou tão versado nas variações 8-). Alguém acabou com voto negativo, quer saber por quê?
slm
2

Isso funciona com o OS X, trmas não com o GNU tr:

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

Isso funciona com gawkmas não com mawkou nawk(que está /usr/bin/awkno OS X):

awk '{print toupper($0)}'

Outra opção é usar o GNU sed:

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

No Bash 4.0 e posterior, você também pode usar a ^^expansão de parâmetro:

while IFS= read -r l;do printf %s\\n "${l^^}";done
nisetama
fonte