O comando cut
tem uma opção -c
para trabalhar em personagens, em vez de bytes com a opção -b
. Mas isso não parece funcionar, no en_US.UTF-8
local:
O segundo byte fornece o segundo caractere ASCII (que é codificado da mesma forma em UTF-8):
$ printf 'ABC' | cut -b 2
B
mas não fornece o segundo dos três caracteres gregos não ASCII no código do idioma UTF-8:
$ printf 'αβγ' | cut -b 2
�
Está tudo bem - é o segundo byte .
Então, olhamos para o segundo caractere :
$ printf 'αβγ' | cut -c 2
�
Isso parece quebrado.
Com algumas experiências, verifica-se que o intervalo 3-4
mostra o segundo caractere:
$ printf 'αβγ' | cut -c 3-4
β
Mas isso é igual aos bytes 3 a 4:
$ printf 'αβγ' | cut -b 3-4
β
Portanto, o valor -c
não é superior ao -b
UTF-8.
Eu esperaria que a configuração de localidade não seja adequada para UTF-8, mas, em comparação, wc
funciona como esperado;
É frequentemente usado para contar bytes, com a opção -c
( --bytes
).
(Observe os nomes das opções confusas.)
$ printf 'αβγ' | wc -c
6
Mas também pode contar caracteres com a opção -m
( --chars
), que simplesmente funciona:
$ printf 'αβγ' | wc -m
3
Portanto, minha configuração parece estar correta - mas algo é especial cut
.
Talvez ele não suporte UTF-8? Mas parece suportar caracteres de vários bytes, caso contrário não precisaria suportar -b
e -c
.
Então, oque há de errado? E porque?
A configuração da localidade parece correta para utf8, até onde eu sei:
$ locale
LANG=en_US.UTF-8
LANGUAGE=en_US
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_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
A entrada, byte a byte:
$ printf 'αβγ' | hd
00000000 ce b1 ce b2 ce b3 |......|
00000006
fonte
-c
está usando o mesmo código que-b
. Você deu uma olhada no código fonte? Talvez você possa encontrar uma dica para o que-c
realmente se destina.Respostas:
Você não disse o que
cut
está usando, mas desde que você mencionou a opção GNU long,--characters
assumirei que é essa. Nesse caso, observe esta passagem deinfo coreutils 'cut invocation'
:(enfase adicionada)
No momento, o GNU
cut
sempre funciona em termos de "caracteres" de byte único, portanto o comportamento que você vê é esperado.O suporte às opções
-b
e-c
é requerido pelo POSIX - eles não foram adicionados ao GNUcut
porque tinham suporte a vários bytes e funcionaram corretamente, mas para evitar erros na entrada compatível com POSIX. O mesmo-c
foi feito em algumas outrascut
implementações, embora não pelo menos no FreeBSD e no OS X.Este é o comportamento histórico de
-c
.-b
foi adicionado recentemente para assumir a função de bytes, para que-c
possa funcionar com caracteres de vários bytes. Talvez em alguns anos funcione conforme desejado de maneira consistente, embora o progresso não tenha sido exatamente rápido (já faz mais de uma década). O GNUcut
ainda nem implementa a-n
opção , apesar de ortogonal e destinada a ajudar na transição. Existem possíveis problemas de compatibilidade com scripts antigos, o que pode ser uma preocupação, embora eu não saiba definitivamente qual é o motivo.fonte
tr
documentos do GNU também. e mesmotar
que eu não me lembre. Eu acho que é um grande projeto.cut
? Por exemplo, onde é possível baixar as fontes de patchescut
? Ou seria mais fácil usar outro utilitário? (agrep
solução abaixo não funciona sem problemas com os intervalos, por exemplo5-8,44-49
)cut -c
aqui: superuser.com/questions/506164/…colrm
(parte deutil-linux
, já deve estar instalado na maioria das distribuições) parece lidar com a internacionalização muito melhor:Cuidado com a numeração:
colrm N
removerá as colunasN
, imprimindo caracteres atéN-1
.( créditos )
fonte
Como muitas
grep
implementações têm reconhecimento multibyte, você também pode usargrep -o
para simular alguns usos decut -c
.Ajuste o número de períodos para simular
cut
intervalos.fonte