Polecenie cut
ma opcję -c
pracy na znakach zamiast bajtów z tą opcją -b
. Ale to wydaje się nie działać, na poziomie en_US.UTF-8
lokalnym:
Drugi bajt podaje drugi znak ASCII (który jest tak samo zakodowany w UTF-8):
$ printf 'ABC' | cut -b 2
B
ale nie podaje drugiego z trzech greckich znaków spoza ASCII w ustawieniach regionalnych UTF-8:
$ printf 'αβγ' | cut -b 2
�
W porządku - to drugi bajt . Zamiast tego
patrzymy na drugą postać :
$ printf 'αβγ' | cut -c 2
�
To wygląda na zepsute.
Po niektórych eksperymentach okazuje się, że zakres 3-4
pokazuje drugą postać:
$ printf 'αβγ' | cut -c 3-4
β
Ale to tak samo, jak w bajtach od 3 do 4:
$ printf 'αβγ' | cut -b 3-4
β
Czyli -c
nie więcej niż -b
dla UTF-8.
Spodziewałbym się, że ustawienia regionalne nie są odpowiednie dla UTF-8, ale dla porównania wc
działają zgodnie z oczekiwaniami;
Jest często używany do liczenia bajtów, z opcją -c
( --bytes
).
(Zwróć uwagę na mylące nazwy opcji).
$ printf 'αβγ' | wc -c
6
Ale może również liczyć znaki za pomocą opcji -m
( --chars
), która po prostu działa:
$ printf 'αβγ' | wc -m
3
Więc moja konfiguracja wydaje się być w porządku - ale coś jest wyjątkowego cut
.
Może wcale nie obsługuje UTF-8? Ale wydaje się, że obsługuje znaki wielobajtowe, w przeciwnym razie nie musiałby obsługiwać znaków -b
i -c
.
Co jest nie tak? I dlaczego?
Konfiguracja regionalna wygląda na utf8, o ile mogę powiedzieć:
$ 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=
Dane wejściowe bajt po bajcie:
$ printf 'αβγ' | hd
00000000 ce b1 ce b2 ce b3 |......|
00000006
-c
to, że używa tego samego kodu co-b
. Czy spojrzałeś na kod źródłowy? Może uda ci się znaleźć wskazówkę, co-c
właściwie jest przeznaczone.