Яке C
значення має LC_ALL
робити в Unix-подібних системах?
Я знаю, що воно має однаковий локал для всіх аспектів, але що C
робити?
Яке C
значення має LC_ALL
робити в Unix-подібних системах?
Я знаю, що воно має однаковий локал для всіх аспектів, але що C
робити?
Відповіді:
Він змушує програми використовувати мову за замовчуванням для виводу:
$ LC_ALL=es_ES man
¿Qué página de manual desea?
$ LC_ALL=C man
What manual page do you want?
і змушує сортування бути байтовим:
$ 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_ALL
- це змінна середовище, яка перекриває всі інші параметри локалізації ( за винятком $LANGUAGE
деяких обставин ).
За допомогою кількох змінних середовища можна встановити різні аспекти локалізації (наприклад, роздільник тисяч чи знаків десяткової крапки, набір символів, порядок сортування, місяць, назви дня, мова чи програми додатків, наприклад повідомлення про помилки, символ валюти).
Зазвичай ви встановлюєте $LANG
свої переваги зі значенням, яке ідентифікує ваш регіон (наприклад, fr_CH.UTF-8
якщо ви перебуваєте у франкомовної Швейцарії, використовуючи UTF-8). Окремі LC_xxx
змінні перекривають певний аспект. LC_ALL
перекриває їх усіх. locale
Команди, при виклику без аргументів дає коротку інформацію про поточні настройки.
Наприклад, у системі GNU я отримую:
$ 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=
Я можу замінити індивідуальне налаштування, наприклад:
$ LC_TIME=fr_FR.UTF-8 date
jeudi 22 août 2013, 10:41:30 (UTC+0100)
Або:
$ LC_MONETARY=fr_FR.UTF-8 locale currency_symbol
€
Або замініть усе за допомогою LC_ALL.
$ LC_ALL=C LANG=fr_FR.UTF-8 LC_MESSAGES=fr_FR.UTF-8 cat /
cat: /: Is a directory
У сценарії, якщо ви хочете застосувати певний параметр, оскільки ви не знаєте, які налаштування примусив користувач (можливо, також LC_ALL), ваш найкращий, найбезпечніший і, як правило, єдиний варіант - це застосувати LC_ALL.
C
Локаль спеціальна мова , який призначається , щоб бути самим простим локалі. Ви також можете сказати, що хоча інші локалі для людей, мова C є для комп'ютерів. У мові C символи - це одиничні байти, набір символів - ASCII (ну, не потрібно, але на практиці буде в системах, які більшість з нас коли-небудь отримає для використання), порядок сортування базується на значеннях байтів, мова зазвичай є англійською мовою США (хоча для повідомлень додатків (на відміну від речей, таких як імена місяця чи дня або повідомлення системних бібліотек), це на розсуд автора програми), і такі речі, як символи валюти, не визначені.
У деяких системах є різниця з локальним пунктом POSIX, де, наприклад, порядок сортування для символів, що не належать до ASCII, не визначений.
Зазвичай ви виконуєте команду з LC_ALL = C, щоб уникнути налаштувань користувача для втручання у ваш сценарій. Наприклад, якщо ви хочете [a-z]
відповідати 26 символам ASCII від a
до z
, вам доведеться встановити LC_ALL=C
.
У системах GNU LC_ALL=C
і LC_ALL=POSIX
(або LC_MESSAGES=C|POSIX
) переосмислити $LANGUAGE
, хоча LC_ALL=anything-else
не буде.
Кілька випадків, коли вам зазвичай потрібно встановити LC_ALL=C
:
sort -u
або sort ... | uniq...
. У багатьох локальних системах, окрім C, у деяких системах (зокрема в GNU) деякі символи мають той самий порядок сортування . sort -u
не повідомляє унікальні рядки, але один з кожної групи рядків, що мають рівний порядок сортування. Отже, якщо ви хочете унікальних ліній, вам потрібна локаль, де символи є байтом, а всі символи мають різний порядок сортування (що C
гарантує локаль).=
оператора сумісного з POSIX expr
або ==
оператора сумісного з POSIX awk
s ( mawk
і gawk
не є POSIX у цьому відношенні), який не перевіряє, чи є два рядки однаковими, але чи сортують вони однакові.grep
. Якщо ви хочете відповідати букві мовою користувача, використовуйте grep '[[:alpha:]]'
та не змінюйте LC_ALL
. Але якщо ви хочете відповідати a-zA-Z
символам ASCII, вам потрібно LC_ALL=C grep '[[:alpha:]]'
або LC_ALL=C grep '[a-zA-Z]'
¹. [a-z]
відповідає символам, які сортуються після a
і раніше z
(хоча з багатьма API це складніше). В інших регіонах ви, як правило, не знаєте, що це. Наприклад, деякі локалі ігнорують випадок для сортування, тому [a-z]
в деяких API, таких як bash
шаблони, можуть бути включені [B-Z]
або [A-Y]
. У багатьох локальних точках UTF-8 (у тому числі en_US.UTF-8
в більшості систем) [a-z]
будуть входити латинські літери від a
до y
діакритики, але не ті, що є z
(оскількиz
сорти перед ними), які я не можу уявити, було б те, що ви хочете (чому б ви хотіли включити, é
а ні ź
?).Арифметика з плаваючою комою в ksh93
. ksh93
відзначає decimal_point
налаштування в LC_NUMERIC
. Якщо ви пишете скрипт, який містить a=$((1.2/7))
, він перестане працювати, коли його виконує користувач, у локалі якого є коска як десятковий роздільник:
$ 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
Тоді вам потрібні такі речі, як:
#! /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
Як бічна примітка: ,
десятковий роздільник конфліктує з ,
арифметичним оператором, що може спричинити ще більше плутанини.
grep '<.*>'
шукати рядки, що містять a <
, >
пара не спрацює, якщо ви знаходитесь у локалі UTF-8 і вхід кодується в однобайтовому 8-бітовому наборі символів типу iso8859-15. Це тому, що .
лише відповідні символи та символи, що не належать до ASCII, в ізо8859-15, ймовірно, не утворюють дійсного символу в UTF-8. З іншого боку, LC_ALL=C grep '<.*>'
буде працювати, тому що будь-яке значення байту утворює дійсний символ у C
локалі.Будь-який час, коли ви обробляєте вхідні дані або вихідні дані, не призначені для / для людини. Якщо ви розмовляєте з користувачем, ви можете скористатися їх умовою та мовою, але, наприклад, якщо ви генеруєте деякі цифри, щоб подати якусь іншу програму, яка очікує десяткових знаків в англійському стилі, або англійські імена місяця, вам потрібно встановити 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
Це також стосується таких речей, як порівняння нечутливих до регістру (наприклад, у grep -i
) та перетворення справ ( awk
's toupper()
, dd conv=ucase
...). Наприклад:
grep -i i
не гарантується відповідність I
у місцевості користувача. У деяких турецьких районах , наприклад, це робить не як великі букви i
є İ
(зверніть увагу на точку) там і рядковим I
є ı
(зверніть увагу на відсутню точку).
Залежно від кодування тексту, це не обов'язково робити правильно. Це справедливо для наборів символів UTF-8 або однобайтових наборів символів (наприклад, iso-8859-1), але необов'язково багатобайтових наборів символів, що не належать до UTF-8.
Наприклад, якщо ви знаходитесь у zh_HK.big5hkscs
місцевому значенні (Гонконг, використовуючи гонконгський варіант кодування китайських символів BIG5), і ви хочете шукати англійські літери у файлі, закодованому в цих діаграм, виконуючи будь-яке:
LC_ALL=C grep '[[:alpha:]]'
або
LC_ALL=C grep '[a-zA-Z]'
було б помилково, тому що в цій наборі (та багатьох інших, але майже не використовуються з моменту виходу UTF-8) багато символів містять байти, що відповідають кодуванню ASCII символів A-Za-z. Наприклад, усі A䨝䰲丕乙乜你再劀劈呸哻唥唧噀噦嚳坽
(та багато іншого) містять кодування A
. 䨝
є 0x96 0x41, і 0x41, A
як в ASCII. Отже, наші LC_ALL=C grep '[a-zA-Z]'
відповідатимуть тим рядкам, які містять ці символи, як би неправильно трактували ці послідовності байтів.
LC_COLLATE=C grep '[A-Za-z]'
працював би, але тільки якщо LC_ALL
інше не встановлено (що би перекрило LC_COLLATE
). Тож вам може знадобитися:
grep '[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]'
якщо ви хотіли шукати англійські літери у файлі, закодованому в кодуванні локалу.
C
потрібна лише для підтримки "портативного набору символів" (ASCII 0-127), а поведінка для символів> 127 технічно не визначено . На практиці більшість програм трактує їх як непрозорі дані та передаватиме їх, як ви описали. Але не все: зокрема, Ruby може задихатися в даних char із байтами> 127, якщо працює в C
локалі. Я, чесно кажучи, не знаю, чи технічно це "відповідне", але ми це бачили в дикій природі .
perl
«з \x{7FFFFFFFFFFFFFFF}
) і в той час як діапазон кодових точок Unicode був довільно обмежений U + 10FFFF (через обмеження дизайну UTF-16) деякі інструменти все ще розпізнають / видають 6 байт-символів. Ось що я мав на увазі під 6 байтовими символами. У семантиці Unix один символ - це одна кодова точка. Ваші більш ніж одні "символи" кодової точки загалом позначаються як кластери графем, щоб роз'єднати їх із символами.
C
є мовою за замовчуванням, "POSIX" - псевдонім "C". Я здогадуюсь, що "C" походить від ANSI-C. Можливо, ANSI-C визначить локальний пункт "POSIX".
C
назва мови походить від "ANSI C".
Наскільки я можу сказати, OS X використовує порядок зіставлення кодових точок у локаціях UTF-8, тож це виняток із деяких пунктів, зазначених у відповіді Стефана Шазеласа.
Це друкує 26 в OS X і 310 в Ubuntu:
export LC_ALL=en_US.UTF-8
printf %b $(printf '\\U%08x\\n' $(seq $((0x11)) $((0x10ffff))))|grep -a '[a-z]'|wc -l
Код нижче нічого не друкує в OS X, вказуючи на те, що вхід сортований. Вилучені шість сурогатних символів викликають помилку помилки послідовності байтів.
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
Код нижче нічого не друкує в OS X, що вказує на відсутність двох послідовних кодових точок (принаймні між U + 000B та U + D7FF), які мають однаковий порядок порівняння.
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
(Наведені вище приклади використовуються, %b
оскільки printf \\U25
призводять до помилки в zsh.)
Деякі символи та послідовності символів, що мають однаковий порядок порівняння в системах GNU, не мають однакового порядку упорядкування в OS X. Це друкується ① спочатку в OS X (використовуючи OS X sort
або GNU sort
), але ② спочатку в Ubuntu:
export LC_ALL=en_US.UTF-8;printf %s\\n ② ①|sort
Це друкує три рядки в OS X (використовуючи OS X sort
або GNU sort
), але один рядок в Ubuntu:
export LC_ALL=en_US.UTF-8;printf %b\\n \\u0d4c \\u0d57 \\u0d46\\u0d57|sort -u
Здається, що також LC_COLLATE
керує "алфавітним порядком", який використовується ls. Місцевість США буде сортована таким чином:
a.C
aFilename.C
aFilename.H
a.H
в основному ігнорування періодів. Ви можете віддати перевагу:
a.C
a.H
aFilename.C
aFilename.H
Я, звичайно, роблю. Установка LC_COLLATE
для C
вирішує цю задачу. Зауважте, що вона також буде сортувати малі регістри після всіх великих літер:
A.C
A.H
AFilename.C
a.C
a.H
xclock
попередженням (Missing charsets in String to FontSet conversion
), буде краще, якщо ви використаєте,LC_ALL=C.UTF-8
щоб уникнути проблем із кирилицею. Щоб встановити цю змінну середовища, потрібно додати наступний рядок до кінця~/.bashrc
файлу -export LC_ALL=C.UTF-8