Do czego służy Cwartość LC_ALLw systemach uniksopodobnych?
Wiem, że wymusza to to samo ustawienie regionalne dla wszystkich aspektów, ale co robi C?
Do czego służy Cwartość LC_ALLw systemach uniksopodobnych?
Wiem, że wymusza to to samo ustawienie regionalne dla wszystkich aspektów, ale co robi C?
Odpowiedzi:
Zmusza aplikacje do używania domyślnego języka danych wyjściowych:
$ LC_ALL=es_ES man
¿Qué página de manual desea?
$ LC_ALL=C man
What manual page do you want?
i wymusza sortowanie bajtowe:
$ LC_ALL=en_US sort <<< $'a\nb\nA\nB'
a
A
b
B
$ LC_ALL=C sort <<< $'a\nb\nA\nB'
A
B
a
b
LC_ALLto zmienna środowiskowa, która zastępuje wszystkie pozostałe ustawienia lokalizacji ( z wyjątkiem $LANGUAGEniektórych okoliczności ).
Różne aspekty lokalizacji (takie jak separator tysięcy lub znak dziesiętny, zestaw znaków, kolejność sortowania, miesiąc, nazwy dni, komunikaty językowe lub aplikacji, takie jak komunikaty o błędach, symbol waluty) można ustawić za pomocą kilku zmiennych środowiskowych.
Zazwyczaj ustawiasz $LANGpreferencje za pomocą wartości identyfikującej twój region (np. fr_CH.UTF-8Jeśli jesteś w francuskojęzycznej Szwajcarii, używając UTF-8). Poszczególne LC_xxxzmienne przesłaniają pewien aspekt. LC_ALLzastępuje je wszystkie. localePoleceń, gdy wywołana bez argumentów przedstawia podsumowanie aktualnych ustawieniach.
Na przykład w systemie GNU otrzymuję:
$ locale
LANG=en_GB.UTF-8
LANGUAGE=
LC_CTYPE="en_GB.UTF-8"
LC_NUMERIC="en_GB.UTF-8"
LC_TIME="en_GB.UTF-8"
LC_COLLATE="en_GB.UTF-8"
LC_MONETARY="en_GB.UTF-8"
LC_MESSAGES="en_GB.UTF-8"
LC_PAPER="en_GB.UTF-8"
LC_NAME="en_GB.UTF-8"
LC_ADDRESS="en_GB.UTF-8"
LC_TELEPHONE="en_GB.UTF-8"
LC_MEASUREMENT="en_GB.UTF-8"
LC_IDENTIFICATION="en_GB.UTF-8"
LC_ALL=
Mogę zastąpić indywidualne ustawienie, na przykład:
$ LC_TIME=fr_FR.UTF-8 date
jeudi 22 août 2013, 10:41:30 (UTC+0100)
Lub:
$ LC_MONETARY=fr_FR.UTF-8 locale currency_symbol
€
Lub zastąp wszystko za pomocą LC_ALL.
$ LC_ALL=C LANG=fr_FR.UTF-8 LC_MESSAGES=fr_FR.UTF-8 cat /
cat: /: Is a directory
W skrypcie, jeśli chcesz wymusić określone ustawienie, ponieważ nie wiesz, jakie ustawienia wymusił użytkownik (prawdopodobnie również LC_ALL), najlepszą, najbezpieczniejszą i ogólnie jedyną opcją jest wymuszenie LC_ALL.
Lokalizacja Cjest specjalną lokalizacją, która ma być najprostszą lokalizacją. Można również powiedzieć, że podczas gdy inne ustawienia narodowe są przeznaczone dla ludzi, ustawienia regionalne C dotyczą komputerów. W ustawieniach regionalnych C znaki są jednobajtowe, zestaw znaków to ASCII (cóż, nie jest to wymagane, ale w praktyce będzie w systemach, z których większość z nas będzie mogła korzystać), kolejność sortowania jest oparta na wartościach bajtów, język jest zwykle w języku angielskim (chociaż w przypadku komunikatów aplikacji (w przeciwieństwie do nazw takich jak nazwy miesięcy lub dni lub wiadomości w bibliotekach systemowych), zależy to od autora aplikacji), a symbole walut nie są zdefiniowane.
W niektórych systemach występuje różnica w ustawieniach regionalnych POSIX, w których na przykład nie zdefiniowano kolejności sortowania znaków spoza ASCII.
Zazwyczaj uruchamiasz polecenie z LC_ALL = C, aby uniknąć ustawień użytkownika, które mogłyby zakłócać twój skrypt. Na przykład, jeśli chcesz [a-z]dopasować 26 znaków ASCII od ado z, musisz ustawić LC_ALL=C.
W systemach GNU LC_ALL=Ci LC_ALL=POSIX(lub LC_MESSAGES=C|POSIX) zastępuj $LANGUAGE, podczas gdy LC_ALL=anything-elsenie.
Kilka przypadków, w których zwykle musisz ustawić LC_ALL=C:
sort -ulub sort ... | uniq.... W wielu lokalizacjach innych niż C, w niektórych systemach (zwłaszcza GNU), niektóre znaki mają tę samą kolejność sortowania . sort -unie zgłasza unikalnych wierszy, ale jeden z każdej grupy wierszy o jednakowej kolejności sortowania. Jeśli więc chcesz mieć unikalne wiersze, potrzebujesz ustawień regionalnych, w których znaki są bajtami, a wszystkie znaki mają inną kolejność sortowania (co Cgwarantuje ustawienie regionalne).=operatora zgodnego z POSIX exprlub ==operatora zgodnego z POSIX awk( mawki gawknie są pod tym względem POSIX), które nie sprawdzają, czy dwa ciągi są identyczne, ale czy sortują to samo.grep. Jeśli chcesz dopasować literę w języku użytkownika, używaj grep '[[:alpha:]]'i nie modyfikuj LC_ALL. Ale jeśli chcesz, aby dopasować a-zA-Zznaki ASCII, trzeba albo LC_ALL=C grep '[[:alpha:]]'czy LC_ALL=C grep '[a-zA-Z]'¹. [a-z]dopasowuje znaki, które sortują po ai przed z(choć w przypadku wielu interfejsów API jest to bardziej skomplikowane). W innych lokalizacjach zazwyczaj nie wiesz, co to są. Na przykład niektóre ustawienia narodowe ignorują wielkość liter podczas sortowania, więc [a-z]w niektórych interfejsach API, takich jak bashwzorce, może zawierać [B-Z]lub [A-Y]. W wielu lokalizacjach UTF-8 (w tym en_US.UTF-8w większości systemów) [a-z]będą zawierać litery łacińskie od ado yz znakami diakrytycznymi, ale nie te z(odzsortuje przed nimi), czego nie wyobrażam sobie, co byś chciał (dlaczego chcesz to uwzględnić, éa nie ź?).arytmetyka zmiennoprzecinkowa w ksh93. ksh93honoruje decimal_pointustawienie w LC_NUMERIC. Jeśli napiszesz skrypt, który zawiera a=$((1.2/7)), przestanie on działać po uruchomieniu przez użytkownika, którego ustawienia regionalne mają przecinek jako separator dziesiętny:
$ ksh93 -c 'echo $((1.1/2))'
0.55
$ LANG=fr_FR.UTF-8 ksh93 -c 'echo $((1.1/2))'
ksh93: 1.1/2: arithmetic syntax error
Potrzebujesz więc takich rzeczy jak:
#! /bin/ksh93 -
float input="$1" # get it as input from the user in his locale
float output
arith() { typeset LC_ALL=C; (($@)); }
arith output=input/1.2 # use the dot here as it will be interpreted
# under LC_ALL=C
echo "$output" # output in the user's locale
Na marginesie: ,separator dziesiętny ,powoduje konflikt z operatorem arytmetycznym, co może powodować jeszcze większe zamieszanie.
grep '<.*>'aby wyszukać wiersze zawierające a <, >para nie będzie działać, jeśli jesteś w ustawieniach regionalnych UTF-8, a dane wejściowe są zakodowane w jednym bajcie 8-bitowym zestawie znaków, takim jak iso8859-15. Jest tak, ponieważ .tylko znaki pasujące i znaki spoza ASCII w iso8859-15 prawdopodobnie nie tworzą prawidłowego znaku w UTF-8. Z drugiej strony LC_ALL=C grep '<.*>'zadziała, ponieważ każda wartość bajtu tworzy poprawny znak w Custawieniach regionalnych.Za każdym razem, gdy przetwarzasz dane wejściowe lub wyjściowe, które nie są przeznaczone dla / dla człowieka. Jeśli rozmawiasz z użytkownikiem, możesz chcieć użyć jego konwencji i języka, ale na przykład, jeśli wygenerujesz pewne liczby, aby nakarmić inną aplikację, która oczekuje kropek dziesiętnych w stylu angielskim lub nazw angielskich miesięcy, możesz ustaw LC_ALL = C:
$ printf '%g\n' 1e-2
0,01
$ LC_ALL=C printf '%g\n' 1e-2
0.01
$ date +%b
août
$ LC_ALL=C date +%b
Aug
Dotyczy to również takich rzeczy, jak porównanie bez rozróżniania wielkości liter (jak w grep -i) i konwersja wielkości liter ( awk's toupper(), dd conv=ucase...). Na przykład:
grep -i i
nie gwarantuje się, że dopasuje się Iw ustawieniach regionalnych użytkownika. Na przykład w niektórych tureckich ustawieniach regionalnych nie jest to tak, że wielkie litery isą tam İ(zwróć uwagę na kropkę), a małe litery Ito ı(zauważ brakującą kropkę).
¹ W zależności od kodowania tekstu niekoniecznie jest to jednak właściwe. Dotyczy to zestawów znaków UTF-8 lub jednobajtowych (takich jak iso-8859-1), ale niekoniecznie zestawów znaków wielobajtowych innych niż UTF-8.
Na przykład, jeśli korzystasz z zh_HK.big5hkscsustawień regionalnych (Hongkong, korzystasz z wariantu Hongkongu chińskiego kodowania znaków BIG5) i chcesz poszukać angielskich liter w pliku zakodowanym w tych zestawach znaków, wykonując:
LC_ALL=C grep '[[:alpha:]]'
lub
LC_ALL=C grep '[a-zA-Z]'
byłoby błędne, ponieważ w tym zestawie znaków (i wielu innych, ale rzadko używanych od czasu pojawienia się UTF-8), wiele znaków zawiera bajty odpowiadające kodowaniu ASCII znaków A-Za-z. Na przykład wszystkie A䨝䰲丕乙乜你再劀劈呸哻唥唧噀噦嚳坽(i wiele innych) zawierają kodowanie A. 䨝to 0x96 0x41 i A0x41 jak w ASCII. Zatem nasze LC_ALL=C grep '[a-zA-Z]'pasowałyby do tych wierszy, które zawierają te znaki, ponieważ błędnie interpretują te sekwencje bajtów.
LC_COLLATE=C grep '[A-Za-z]'
działałoby, ale tylko wtedy, gdy LC_ALLnie jest inaczej ustawione (co zastąpiłoby LC_COLLATE). Więc możesz skończyć z koniecznością:
grep '[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]'
jeśli chcesz poszukać angielskich liter w pliku zakodowanym w kodowaniu ustawień regionalnych.
Cregionalne są wymagane tylko do obsługi „przenośnego zestawu znaków” (ASCII 0-127), a zachowanie znaków> 127 jest technicznie nieokreślone . W praktyce większość programów traktuje je jako nieprzejrzyste dane i przekazuje je zgodnie z opisem. Ale nie wszystkie: w szczególności Ruby może zadławić się danymi char o bajtach> 127, jeśli działa w Custawieniach narodowych. Naprawdę nie wiem, czy to technicznie „zgodne”, ale widzieliśmy to na wolności .
perl„s \x{7FFFFFFFFFFFFFFF}), a gdy zakres unikodowe punktów kod został dowolnie ograniczony U + 10FFFF (z powodu ograniczeń projektowych UTF-16), niektóre narzędzia nadal rozpoznają / tworzą 6-bajtowe znaki. To właśnie miałem na myśli 6 bajtowych znaków. W semantyce uniksowej jeden znak jest jednym punktem kodowym. Twoje więcej niż jeden punkt kodowy „znaki” są bardziej ogólnie określany jako klastry graphem disambiguate z postaciami.
Cto domyślne ustawienie narodowe, „POSIX” to alias „C”. Chyba „C” pochodzi od ANSI-C. Może ANSI-C zdefiniuje ustawienia regionalne „POSIX”.
Cnazwa ustawień regionalnych pochodzi od „ANSI C”.
O ile mogę stwierdzić, OS X używa porządku sortowania punktów kodowych w ustawieniach regionalnych UTF-8, więc jest to wyjątek od niektórych punktów wymienionych w odpowiedzi Stéphane Chazelas.
Wypisuje 26 w OS X i 310 w Ubuntu:
export LC_ALL=en_US.UTF-8
printf %b $(printf '\\U%08x\\n' $(seq $((0x11)) $((0x10ffff))))|grep -a '[a-z]'|wc -l
Poniższy kod nie drukuje nic w OS X, co wskazuje, że dane wejściowe są posortowane. Sześć usuniętych znaków zastępczych powoduje błąd niedozwolonej sekwencji bajtów.
export LC_ALL=en_US.UTF-8
for ((i=1;i<=0x1fffff;i++));do
x=$(printf %04x $i)
[[ $x = @(000a|d800|db7f|db80|dbff|dc00|dfff) ]]&&continue
printf %b \\U$x\\n
done|sort -c
Poniższy kod nie drukuje nic w OS X, co wskazuje, że nie ma dwóch kolejnych punktów kodu (przynajmniej między U + 000B i U + D7FF), które mają tę samą kolejność sortowania.
export LC_ALL=en_US.UTF-8
for ((i=0xb;i<=0xd7fe;i++));do
printf %b $(printf '\\U%08x\\n' $((i+1)) $i)|sort -c 2>/dev/null&&echo $i
done
(W powyższych przykładach użyto, %bponieważ printf \\U25powoduje błąd w zsh.)
Niektóre znaki i sekwencje znaków, które mają tę samą kolejność sortowania w systemach GNU, nie mają tej samej kolejności sortowania w OS X. Spowoduje to wydrukowanie ① najpierw w OS X (używając OS X sortlub GNU sort), ale ② najpierw w Ubuntu:
export LC_ALL=en_US.UTF-8;printf %s\\n ② ①|sort
Spowoduje to wydrukowanie trzech linii w systemie OS X (przy użyciu systemu OS X sortlub GNU sort), ale jednej linii w systemie Ubuntu:
export LC_ALL=en_US.UTF-8;printf %b\\n \\u0d4c \\u0d57 \\u0d46\\u0d57|sort -u
Wygląda na to, że LC_COLLATEkontroluje również „kolejność alfabetyczną” używaną przez ls. Ustawienia regionalne w USA będą sortowane w następujący sposób:
a.C
aFilename.C
aFilename.H
a.H
w zasadzie ignorując kropki. Może wolisz:
a.C
a.H
aFilename.C
aFilename.H
Na pewno tak. Ustawienie LC_COLLATEdo Cosiągnięcia tego. Zauważ, że sortuje również małe litery po wszystkich wielkich literach:
A.C
A.H
AFilename.C
a.C
a.H
xclockostrzeżeniem (Missing charsets in String to FontSet conversion), lepiej będzie, jeśli użyjesz go,LC_ALL=C.UTF-8aby uniknąć problemów z cyrylicą. Aby ustawić tę zmienną środowiskową, musisz dodać następujący wiersz na końcu~/.bashrcpliku -export LC_ALL=C.UTF-8