在类似Unix的系统中,CLC_ALL值有什么作用?

我知道它在所有方面都强制使用相同的语言环境,但是C的作用是什么?

评论

如果要解决xclock警告的问题(在String到FontSet转换中缺少字符集),则最好使用LC_ALL = C.UTF-8来避免西里尔字母的问题。要设置此环境变量,必须将以下行添加到〜/ .bashrc文件的末尾-导出LC_ALL = C.UTF-8

@fedotsoldier,您可能应该提出问题并自己给出答案,我认为这与问题无关。只是解决您遇到的其他问题。

是的,你是对的,好

#1 楼

它强制应用程序使用默认语言输出:

$ 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


评论


+1是一个很好的范例,但缺少Stephane回答中的重要信息...

–奥利维尔·杜拉克(Olivier Dulac)
13年8月22日在11:06

默认语言是什么意思?

–StéphaneChazelas
2014-09-10 14:59

是的,我知道作者可以做他喜欢做的任何事情,包括不能做锡上写的。事情是。在LC_ALL = C中,美国英语是唯一可以用字符集正确表示的语言,在LC_ALL = C(LC_COLLATE)中排序顺序有意义的唯一语言,LC_ALL = C(LC_TIME)具有英语月份和日期名称。我从未见过LC_ALL = C以不同于LC_ALL = en LANGUAGE = en的语言返回消息的应用程序。如果不是这种情况,我是否有权报告程序错误? (此处不谈论未翻译成英文的应用程序)。

–StéphaneChazelas
2014-09-10 19:55

问题是“美国英语是唯一可以用LC_ALL = C中的字符集正确表示的语言”。这通常仅在使用窄字符的C / C ++程序中适用,但即使如此,也存在例外(因为有几种语言仅使用ASCII中的字符和符号)。如果默认语言不是英语,则报告错误会使您显得...偏执。

–伊格纳西奥·巴斯克斯(Ignacio Vazquez-Abrams)
2014-09-10 22:37

请注意,在英语中(含义为LANG = en_US.utf8),消息可以(并且应该)使用Unicode字符(例如“”)来引用字符串。而在LANG = C中,它仅包含ASCII(双引号,反引号和撇号)。

–Ángel
15年3月10日在16:55

#2 楼

LC_ALL是覆盖所有其他本地化设置(在某些情况下为$LANGUAGE除外)的环境变量。

本地化的各个方面(例如千位分隔符或小数点字符,字符集,排序顺序,月份,您可以使用一些环境变量来设置日期名称,语言或应用程序消息,例如错误消息,货币符号。 (如果您在讲法语的瑞士,请使用UTF-8)。各个$LANG变量会覆盖某个方面。 fr_CH.UTF-8覆盖所有。 LC_xxx命令在不带参数的情况下给出了当前设置的摘要。例如,在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_ALL进行所有操作。

$ LC_MONETARY=fr_FR.UTF-8 locale currency_symbol
€


在脚本中,如果您要强制执行特定设置,因为您不知道用户强制执行了哪些设置(可能将LC_ALL那么,最好,最安全且通常唯一的选择是强制使用LC_ALL。

LC_ALL语言环境是特殊的语言环境,它是最简单的语言环境。您还可以说,其他语言环境适用于人类,而C语言环境适用于计算机。在C语言环境中,字符是单个字节,字符集是ASCII(不是必需的,但实际上将在我们大多数人都可以使用的系统中使用),排序顺序基于字节值,该语言通常是美国英语(尽管对于应用程序消息(与月份或日期名称或系统库中的消息相反),这由应用程序作者自行决定),并且未定义货币符号之类的内容。

在某些系统上,与POSIX区域设置有所不同,例如未定义非ASCII字符的排序顺序。

通常使用LC_ALL = C运行命令以避免用户的设置干扰与您的脚本。例如,如果希望locale匹配C[a-z]中的26个ASCII字符,则必须设置a

在GNU系统上,zLC_ALL=C(或LC_ALL=C)会覆盖LC_ALL=POSIX,而LC_MESSAGES=C|POSIX不会t。

通常需要设置$LANGUAGE的几种情况:



LC_ALL=anything-elseLC_ALL=C在C以外的许多语言环境中,在某些系统(尤其是GNU语言)上,某些字符具有相同的排序顺序。 sort -u不会报告唯一行,但是会报告每组具有相同排序顺序的行。因此,如果您确实想要唯一的行,则需要一个字符为字节且所有字符具有不同排序顺序的语言环境(sort ... | uniq...语言环境保证)。
同样适用于POSIX兼容的sort -u运算符或兼容POSIX的C(在这方面=expr不是POSIX),它们不检查两个字符串是否相同,但它们是否排序相同。
字符范围如==中。如果要匹配用户语言中的字母,请使用awk,不要修改mawk。但是,如果要匹配gawk ASCII字符,则需要grepgrep '[[:alpha:]]'¹。 LC_ALL与在a-zA-Z之后和LC_ALL=C grep '[[:alpha:]]'之前排序的字符匹配(尽管使用许多API更为复杂)。在其他语言环境中,您通常不知道它们是什么。例如,某些语言环境会忽略大小写排序,因此某些API中的LC_ALL=C grep '[a-zA-Z]'(例如[a-z]模式)可能包括az。在许多UTF-8语言环境中(大多数系统上包括[a-z]),bash会包含从[B-Z][A-Y]的带有变音符号的拉丁字母,但不会包含en_US.UTF-8的拉丁字母(因为[a-z]排在前面),我无法想象这是您想要的(为什么要包含a而不包含y?)。

z中的浮点算法。 z支持é中的ź设置。如果编写的脚本包含ksh93,则当由语言环境以逗号作为小数点分隔符的用户运行时,该脚本将停止工作:

$ LC_ALL=C LANG=fr_FR.UTF-8 LC_MESSAGES=fr_FR.UTF-8 cat /
cat: /: Is a directory


作为一个补充说明:ksh93小数点分隔符与decimal_point算术运算符冲突,这会引起更多混乱。

当您需要字符为字节。如今,大多数语言环境都基于UTF-8,这意味着字符可以占用1到6个字节。在使用文本实用程序处理本应为字节的数据时,您需要设置LC_ALL = C。由于解析UTF-8数据会产生成本,因此它还将显着提高性能。
上一点的推论:处理文本时,您不知道输入的字符集是什么,但可以假定它与ASCII兼容(因为几乎所有字符集都是如此)。例如,使用LC_NUMERIC查找包含a=$((1.2/7))的行,如果您使用的是UTF-8语言环境,并且输入编码为单字节8位字符集(如iso8859-15),则,对将无效。这是因为,仅匹配字符,而iso8859-15中的非ASCII字符可能不会在UTF-8中形成有效字符。另一方面,grep '<.*>'将起作用,因为任何字节值都在<语言环境中形成有效字符。

任何时候您处理输入数据或输出数据都不是人类所期望的。如果您正在与用户交谈,则可能要使用他们的约定和语言,但是,例如,如果您生成一些数字以供其他需要英语小数点或英语月份名称的应用程序使用,设置LC_ALL = C:

$ 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


这也适用于不区分大小写的比较(例如>)和大小写转换(.LC_ALL=C grep '<.*>'C ...) 。例如:

#! /bin/ksh93 -
float input="" # 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 -i匹配。例如,在某些土耳其语语言环境中,大写awk不是toupper()(请注意点),小写dd conv=ucaseI(请注意缺少点)。



¹根据文本的编码,这不一定是正确的选择。这适用于UTF-8或单字节字符集(如iso-8859-1),但不一定非UTF-8多字节字符集。

例如,如果您使用的是i语言环境(香港,使用BIG5中文字符编码的香港变体),并且您想要在以该字符集编码的文件中查找英文字母,请执行以下任一操作:

$ 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 i


是错误的,因为在该字符集中(还有许多其他字符,但自从UTF-8出现以来就很少使用),很多字符包含对应的字节到A-Za-z字符的ASCII编码。例如,所有İ(以及更多)都包含I的编码。 ı是0x96 0x41,而zh_HK.big5hkscs是0x41,类似于ASCII。因此,我们的A䨝䰲丕乙乜你再劀劈呸哻唥唧噀噦嚳坽将在包含那些字符的行上匹配,因为这会误解这些字节序列。

LC_ALL=C grep '[[:alpha:]]'


可以工作,但前提是没有另外设置A(这将覆盖)。因此,您可能最终不得不执行以下操作:

LC_ALL=C grep '[a-zA-Z]'


如果要在以语言环境编码编码的文件中查找英文字母。

评论


+1,这是最好的答案(用于指出覆盖等)。但是缺少伊格纳西奥答案的(很好)例子^^

–奥利维尔·杜拉克(Olivier Dulac)
13年8月22日在11:08

次要的选择:仅要求C语言环境支持“便携式字符集”(ASCII 0-127),并且chars> 127的行为在技术上未指定。实际上,大多数程序会将它们视为不透明数据,并按照您所描述的那样传递它们。但不是全部:特别是,如果在C语言环境中运行,Ruby可能会阻塞字节数大于127的char数据。老实说,我不知道这在技术上是否“合格”,但我们已经在野外看到了。

–安德鲁·扬克(Andrew Janke)
15年12月16日在19:26

@AndrewJanke,是的。请注意,可移植字符集并不意味着ASCII或0-127。在奥斯汀小组邮件列表上,已经有很多关于“ C”区域设置字符集的属性是什么的讨论,并且普遍的共识(将在下一个规范中阐明)是该字符集是单字符集,字节,并包含完整的8位范围(具有此处描述的属性)。同时,是的,可能会有一些差异(例如错误或由于规范不够明确)。无论如何,LC_ALL = C是最接近您理智的行为。

–StéphaneChazelas
2015年12月16日20:11



UTF-8中的Unicode代码点最多可以包含4个八位位组(或字节),但是某些字符需要一个以上的代码点,这可能导致比6个八位位组更长的序列。

– 12431234123412341234123
17年4月18日在17:15

@ 124312341234123412341234123,原始UTF-8编码最多可覆盖U + 7FFFFFFF(6个字节,并且有些扩展名可以扩展到13个字节,例如perl的\ x {7FFFFFFFFFFFFFFF}),并且Unicode代码点的范围已受到任意限制到U + 10FFFF(由于UTF-16设计限制),某些工具仍可识别/产生6个字节的字符。这就是6​​字节字符的意思。在Unix语义中,一个字符是一个代码点。您的多个代码点“字符”通常被称为字素簇,以消除字符歧义。

–StéphaneChazelas
17-4-18在17:42



#3 楼

C是默认语言环境,“ POSIX”是“ C”的别名。我猜“ C”是从ANSI-C派生的。也许ANSI-C定义了“ POSIX”语言环境。

评论


C和UNIX都早于ANSIC。

–用户
13年8月22日在10:55

@MichaelKjörling:是吗?我看过ANSI以前的文档,但没有语言环境。在AT&T贝尔实验室内部,每个人都说英语。

– MSalters
13年8月22日在14:50

@MSalters C语言的ANSI之前的文档没有提及语言环境的事实(这可能或可能不表示ANSI之前的C语言没有语言环境的概念;毕竟,我敢肯定,该语言仍然没有,但这并不重要)并不意味着C语言环境名称源自“ ANSI C”。

–用户
13年8月22日在21:18

@MichaelKjörling:您错过了重点。引入语言环境时,“ C”已经表示“ ANSI C”。那意味着过去的K&R C是无关紧要的。

– MSalters
13年8月23日在7:36

#4 楼

据我所知,OS X在UTF-8语言环境中使用代码点排序规则,因此,这是StéphaneChazelas的答案中提到的一些要点的例外。 Ubuntu中的OS X和310:

 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中打印一行: br />
 export LC_ALL=en_US.UTF-8;printf %b\n \u0d4c \u0d57 \u0d46\u0d57|sort -u
 


评论


有谁知道为什么会有这种区别?

–1.61803
19年2月23日在9:49

#5 楼

看来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