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
źródło
-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.Odpowiedzi:
Nie powiedziałeś, którego
cut
używasz, ale skoro wspomniałeś o opcji długiego GNU--characters
, zakładam, że to ta. W takim przypadku zwróć uwagę na ten fragment zinfo coreutils 'cut invocation'
:(podkreślenie dodane)
W tej chwili GNU
cut
zawsze działa w kategoriach jednobajtowych „znaków”, więc oczekiwane zachowanie jest oczekiwane.Obsługa zarówno opcji, jak
-b
i-c
opcji jest wymagana przez POSIX - nie zostały dodane do GNU,cut
ponieważ miały obsługę wielu bajtów i działały poprawnie, ale aby uniknąć błędów w danych wejściowych zgodnych z POSIX. To samo-c
zostało zrobione w niektórych innychcut
implementacjach, chociaż przynajmniej nie FreeBSD i OS X.Jest to historyczny zachowanie od
-c
.-b
został niedawno dodany, aby przejąć rolę bajtu, dzięki czemu-c
może pracować ze znakami wielobajtowymi. Może za kilka lat będzie działał zgodnie z oczekiwaniami, chociaż postęp nie był tak szybki (minęło już ponad dekadę). GNUcut
nawet jeszcze nie implementuje tej-n
opcji , chociaż jest ortogonalna i ma na celu pomóc w przejściu. Istnieją potencjalne problemy ze zgodnością ze starymi skryptami, które mogą stanowić problem, chociaż nie wiem ostatecznie, jaki jest tego powód.źródło
tr
dokumentach GNU . i nawettar
jeśli źle się nie zapamiętam. Myślę, że to duży projekt.cut
? Na przykład, gdzie można pobrać źródła łatanecut
? A może łatwiej byłoby użyć innego narzędzia? (grep
poniższe rozwiązanie nie działa płynnie z zakresami np.5-8,44-49
)cut -c
tutaj: superuser.com/questions/506164/…colrm
(częśćutil-linux
, powinna być już zainstalowana w większości dystrybucji) wydaje się znacznie lepiej radzić sobie z internacjonalizacją:Uwaga na numerację:
colrm N
usunie kolumny zN
, drukuje znaki doN-1
.( kredyty )
źródło
Ponieważ wiele
grep
implementacji obsługuje wiele bajtów, możesz także użyć ichgrep -o
do symulacji niektórych zastosowańcut -c
.Dostosuj liczbę okresów, aby zasymulować
cut
zakresy.źródło