Какое 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
to 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
( 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 в iso8859-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 и A
0x41 как в 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
warning (Missing charsets in String to FontSet conversion
), будет лучше, если вы будете использовать ее,LC_ALL=C.UTF-8
чтобы избежать проблем с кириллицей. Чтобы установить эту переменную среды, вы должны добавить следующую строку в конец~/.bashrc
файла -export LC_ALL=C.UTF-8