jcu*_*bic 409 environment-variables locale
在类 Unix 系统中的C值是LC_ALL什么?
我知道它对所有方面都强制使用相同的语言环境,但是有什么作用C呢?
Sté*_*las 428
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=
Run Code Online (Sandbox Code Playgroud)
例如,我可以覆盖单个设置:
$ LC_TIME=fr_FR.UTF-8 date
jeudi 22 août 2013, 10:41:30 (UTC+0100)
Run Code Online (Sandbox Code Playgroud)
或者:
$ LC_MONETARY=fr_FR.UTF-8 locale currency_symbol
€
Run Code Online (Sandbox Code Playgroud)
或者用 LC_ALL 覆盖所有内容。
$ LC_ALL=C LANG=fr_FR.UTF-8 LC_MESSAGES=fr_FR.UTF-8 cat /
cat: /: Is a directory
Run Code Online (Sandbox Code Playgroud)
在脚本中,如果您想强制进行特定设置,因为您不知道用户强制进行了哪些设置(也可能是 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) override $LANGUAGE,而LC_ALL=anything-else不会。
您通常需要设置的几种情况LC_ALL=C:
sort -u或sort ... | uniq...。在 C 以外的许多语言环境中,在某些系统(特别是 GNU 系统)上,某些字符具有相同的排序顺序。sort -u不报告唯一的行,而是报告具有相同排序顺序的每组行中的一个。因此,如果您确实需要唯一的行,则需要一个字符为字节且所有字符具有不同排序顺序的C语言环境(语言环境保证这一点)。
这同样适用于=符合POSIX标准的运营商expr或==与POSIX兼容的操作awk秒(mawk和gawk不POSIX在这方面),不检查两个字符串是否相同,但他们是否排序相同。
字符范围如 in grep。如果您想匹配用户语言中的字母,请使用grep '[[:alpha:]]'而不是修改LC_ALL. 但是如果要匹配a-zA-ZASCII 字符,则需要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]将包括拉丁字母 from atoy和变音符号,但不包括那些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
Run Code Online (Sandbox Code Playgroud)
然后你需要这样的东西:
#! /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
Run Code Online (Sandbox Code Playgroud)
附带说明:,小数点分隔符与,算术运算符冲突,这可能会导致更多混淆。
当您需要字符为字节时。如今,大多数语言环境都基于 UTF-8,这意味着字符可以占用 1 到 6 个字节³。当使用文本实用程序处理打算是字节的数据时,您需要设置 LC_ALL=C。它还将显着提高性能,因为解析 UTF-8 数据是有成本的。
上一点的推论:在处理文本时,您不知道输入是用什么字符集写入的,但可以假设它与 ASCII 兼容(几乎所有字符集都是如此)。例如,grep '<.*>'要查找包含<, >pair 的行,如果您在 UTF-8 语言环境中并且输入以单字节 8 位字符集(如 iso8859-15)编码,则该行将不起作用。那是因为.在 iso8859-15 中仅匹配字符和非 ASCII 字符可能不会在 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
Run Code Online (Sandbox Code Playgroud)
这也适用于不区分大小写的比较(如 in grep -i)和大小写转换(awk's toupper(),dd conv=ucase...)。例如:
grep -i i
Run Code Online (Sandbox Code Playgroud)
不能保证I在用户的语言环境中匹配。在比如一些土耳其语言环境,它没有为大写的i是?(注意点)有和小写I是?(注漏点)。
¹ 再次,仅在基于 ASCII 的系统(绝大多数系统)上。POSIX 要求 C 语言环境的整理顺序与 ASCII 字符集中的字符顺序相同,即使在不允许在 C 语言环境中进行strcoll()===strcmp()优化的EBCDIC 系统上也是如此。
² 根据文本的编码,这不一定是正确的做法。这对 UTF-8 或单字节字符集(如 iso-8859-1)有效,但不一定适用于非 UTF-8 多字节字符集。
例如,如果您在zh_HK.big5hkscs区域设置中(香港,使用 BIG5 中文字符编码的香港变体),并且您想在以该字符集编码的文件中查找英文字母,请执行以下任一操作:
LC_ALL=C grep '[[:alpha:]]'
Run Code Online (Sandbox Code Playgroud)
或者
LC_ALL=C grep '[a-zA-Z]'
Run Code Online (Sandbox Code Playgroud)
将是错误的,因为在该字符集中(以及许多其他字符集,但自从 UTF-8 出现后就很少使用了),很多字符包含与 A-Za-z 字符的 ASCII 编码相对应的字节。例如,所有A?????????????????(以及更多)都包含A. ?是 0x96 0x41,和AASCII 一样是 0x41。所以我们LC_ALL=C grep '[a-zA-Z]'会匹配那些包含这些字符的行,因为它会误解这些字节序列。
LC_COLLATE=C grep '[A-Za-z]'
Run Code Online (Sandbox Code Playgroud)
会起作用,但前提LC_ALL是没有另外设置(这会覆盖LC_COLLATE)。所以你最终可能不得不这样做:
grep '[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]'
Run Code Online (Sandbox Code Playgroud)
如果您想在以区域设置编码的文件中查找英文字母。
³ 有些人会争辩说,现在 Unicode 代码点(以及编码/解码 UTF-8 数据的库)被任意限制为代码点 U+0000 到 U+10FFFF(不包括 0xD800 到 0xDFFF),现在它是 1 到 4 个字节从 U+7FFFFFFF 向下以适应 UTF-16 编码,但一些应用程序仍然可以愉快地编码/解码 6 字节 UTF-8 序列(包括落在 0xD800 .. 0xDFFF 范围内的序列)。
Ign*_*ams 266
它强制应用程序使用默认语言进行输出:
$ LC_ALL=es_ES man
¿Qué página de manual desea?
$ LC_ALL=C man
What manual page do you want?
Run Code Online (Sandbox Code Playgroud)
并强制按字节排序:
$ 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
Run Code Online (Sandbox Code Playgroud)
Edw*_*hen 10
C是默认语言环境,“POSIX”是“C”的别名。我猜“C”是从 ANSI-C 派生出来的。也许 ANSI-C 定义了“POSIX”语言环境。
据我所知,OS X 在 UTF-8 语言环境中使用代码点整理顺序,因此它是 Stéphane Chazelas 的答案中提到的一些要点的一个例外。
这在 OS X 中打印 26,在 Ubuntu 中打印 310:
export LC_ALL=en_US.UTF-8
printf %b $(printf '\\U%08x\\n' $(seq $((0x11)) $((0x10ffff))))|grep -a '[a-z]'|wc -l
Run Code Online (Sandbox Code Playgroud)
下面的代码在 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
Run Code Online (Sandbox Code Playgroud)
下面的代码在 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
Run Code Online (Sandbox Code Playgroud)
(上面的例子使用%b因为printf \\U25在 zsh 中导致错误。)
在 GNU 系统中具有相同整理顺序的某些字符和字符序列在 OS X 中没有相同的整理顺序。这会打印 ? 首先在 OS X 中(使用 OS Xsort或 GNU sort)但是?首先在 Ubuntu 中:
export LC_ALL=en_US.UTF-8;printf %s\\n ? ?|sort
Run Code Online (Sandbox Code Playgroud)
这会在 OS X 中打印三行(使用 OS Xsort或 GNU sort),但在 Ubuntu 中打印一行:
export LC_ALL=en_US.UTF-8;printf %b\\n \\u0d4c \\u0d57 \\u0d46\\u0d57|sort -u
Run Code Online (Sandbox Code Playgroud)
小智 5
似乎也LC_COLLATE控制了 ls 使用的“字母顺序”。美国语言环境将按如下方式排序:
a.C
aFilename.C
aFilename.H
a.H
Run Code Online (Sandbox Code Playgroud)
基本上忽略了时期。您可能更喜欢:
a.C
a.H
aFilename.C
aFilename.H
Run Code Online (Sandbox Code Playgroud)
我当然知道。设置LC_COLLATE来C实现这一点。请注意,它还会在所有大写字母之后对小写字母进行排序:
A.C
A.H
AFilename.C
a.C
a.H
Run Code Online (Sandbox Code Playgroud)