勘误,之前这篇文章有错误 http://www.01happy.com/p3204/
问题不是系统自身编码问题,是不同系统的local登录衔接问题。
locale问题起因
登录 centos7 系统时,命令行模式下会出现一个警告:
[bash]
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
[/bash]
这个不是由于系统默认编码问题导致的,这个是因为两台电脑连接时,本地编码不能协调导致的,分析如下:
centos本机登录(没报错)
[root@localhost ~]# locale LANG=en_US.UTF-8 LC_CTYPE="en_US.UTF-8" LC_NUMERIC="en_US.UTF-8" LC_TIME="en_US.UTF-8" LC_COLLATE="en_US.UTF-8" LC_MONETARY="en_US.UTF-8" LC_MESSAGES="en_US.UTF-8" LC_PAPER="en_US.UTF-8" LC_NAME="en_US.UTF-8" LC_ADDRESS="en_US.UTF-8" LC_TELEPHONE="en_US.UTF-8" LC_MEASUREMENT="en_US.UTF-8" LC_IDENTIFICATION="en_US.UTF-8" LC_ALL= [root@localhost ~]#
mac本机登录(没报错)
mbpdeMacBook-Pro:~ cool$ locale LANG= LC_COLLATE="C" LC_CTYPE="UTF-8" LC_MESSAGES="C" LC_MONETARY="C" LC_NUMERIC="C" LC_TIME="C" LC_ALL= mbpdeMacBook-Pro:~ cool$
mac连接centos登录(报错了)
[root@localhost ~]# locale locale: Cannot set LC_CTYPE to default locale: No such file or directory locale: Cannot set LC_ALL to default locale: No such file or directory LANG=en_US.UTF-8 LC_CTYPE=UTF-8 LC_NUMERIC="en_US.UTF-8" LC_TIME="en_US.UTF-8" LC_COLLATE="en_US.UTF-8" LC_MONETARY="en_US.UTF-8" LC_MESSAGES="en_US.UTF-8" LC_PAPER="en_US.UTF-8" LC_NAME="en_US.UTF-8" LC_ADDRESS="en_US.UTF-8" LC_TELEPHONE="en_US.UTF-8" LC_MEASUREMENT="en_US.UTF-8" LC_IDENTIFICATION="en_US.UTF-8" LC_ALL= [root@localhost ~]#
locale背景知识
locale基本含义
locale就是某一个地域内的人们的语言习惯和文化传统和生活习惯。一个地区的locale就是根据这几大类的习惯定义的,这些locale定 义文件放在/usr/share/i18n/locales目录下面,例如en_US, zh_CN and de_DE@euro都是locale的定义文件,这些文件都是用文本格式书写的,你可以用写字板打开,看看里边的内容,当然出了有限的注释以外,大部分 东西可能你都看不懂,因为是用的Unicode的字符索引方式。
cat /usr/share/i18n/locales/zh_CN comment_char % escape_char / % % Chinese language locale for the Peoples Republic of China % % This work is based on ISO PDTR 14652, Unicode 3.0, locale definition % file for zh_CN revision 1.0 ([email protected], 1999-04-28) and % charmap file for GBK version 1.0 ([email protected]). % % The file is designed to work with multiple charsets. To ease the % maintance and adding support for new charsets, all characters are % in UCS notation and presented in Unicode order. % % Changelog: % Tue Jul 25 2000 Yong Li <[email protected]> % - first version for glibc 2.2 。。。。。。 。。。
locale内容说明
[oracle@game ~]$ locale LANG=en_US.UTF-8 LC_CTYPE="en_US.UTF-8" LC_NUMERIC="en_US.UTF-8" LC_TIME="en_US.UTF-8" LC_COLLATE="en_US.UTF-8" LC_MONETARY="en_US.UTF-8" LC_MESSAGES="en_US.UTF-8" LC_PAPER="en_US.UTF-8" LC_NAME="en_US.UTF-8" LC_ADDRESS="en_US.UTF-8" LC_TELEPHONE="en_US.UTF-8" LC_MEASUREMENT="en_US.UTF-8" LC_IDENTIFICATION="en_US.UTF-8" LC_ALL=en_US.UTF-8 [oracle@game ~]$ locale把按照所涉及到的文化传统的各个方面分成12个大类,这12个大类分别是: 1、语言符号及其分类(LC_CTYPE) 2、数字(LC_NUMERIC) 3、比较和排序习惯(LC_COLLATE) 4、时间显示格式(LC_TIME) 5、货币单位(LC_MONETARY) 6、信息主要是提示信息,错误信息,状态信息,标题,标签,按钮和菜单等(LC_MESSAGES) 7、姓名书写方式(LC_NAME) 8、地址书写方式(LC_ADDRESS) 9、电话号码书写方式(LC_TELEPHONE) 10、度量衡表达方式 (LC_MEASUREMENT) 11、默认纸张尺寸大小(LC_PAPER) 12、对locale自身包含信息的概述(LC_IDENTIFICATION)。
locale格式说明
zh_CN.GB2312到底是在说什么?
Locale是软件在运行时的语言环境, 它包括语言(Language), 地域 (Territory) 和字符集(Codeset)。
一个locale的书写格式为: 语言[_地域[.字符集]]。所以说呢,locale总是和一定的字符集相联系的。
下面举几个例子:
1、我说中文,身处中华人民共和国,使用国标2312字符集来表达字符。zh_CN.GB2312=中文_中华人民共和国+国标2312字符集。
2、我说中文,身处中华人民共和国,使用国标18030字符集来表达字符。zh_CN.GB18030=中文_中华人民共和国+国标18030字符集。
3、我说中文,身处中华人民共和国台湾省,使用国标Big5字符集来表达字符。zh_TW.BIG5=中文_台湾.大五码字符集
4、我说英文,身处大不列颠,使用ISO-8859-1字符集来表达字符。 en_GB.ISO-8859-1=英文_大不列颠.ISO-8859-1字符集
5、我说德语,身处德国,使用UTF-8字符集,习惯了欧洲风格。de_DE.UTF-8@euro=德语_德国.UTF-8字符集@按照欧洲习惯加以修正,注意不是[email protected],所以完全的locale表达方式是 [语言[_地域][.字符集] [@修正值]。
对于de_DE@euro的一点说明,@后边是修正项,也就是说你可以看到两个德国的locale:/usr/share/i18n/locales /de_DE@euro和/usr/share/i18n/locales/de_DE。
打开这两个locale定义,你就会知道它们的差别在于 de_DE@euro使用的是欧洲的排序、比较和缩进习惯,而de_DE用的是德国的标准习惯。
locale优先级说明
设定locale就是设定12大类的locale分类属性,即12个LC_*。除了这12个变量可以设定以外,为了简便起见,还有两个变量:LC_ALL和LANG。它们之间有一个优先级的关系:LC_ALL > LC_* >LANG。可以这么说,LC_ALL是最上级设定或者强制设定,而LANG是默认设定值。
1、如果你设定了LC_ALL=zh_CN.UTF-8,那么不管LC_*和LANG设定成什么值,它们都会被强制服从LC_ALL的设定,成为 zh_CN.UTF-8。
2、假如你设定了LANG=zh_CN.UTF-8,而其他的LC_*=en_US.UTF-8,并且没有设定LC_ALL的话,那么系统的locale设定以LC_*=en_US.UTF-8。
3、假如你设定了LANG=zh_CN.UTF-8,而其他的LC_*,和LC_ALL均未设定的话,系统会将LC_*设定成默认值,也就是LANG的值zh_CN.UTF-8。
4、假如你设定了LANG=zh_CN.UTF-8,而其他的LC_CTYPE=en_US.UTF-8,其他的LC_*,和LC_ALL均未设定的话, 那么系统的locale设定将是:LC_CTYPE=en_US.UTF-8,其余的 LC_COLLATE,LC_MESSAGES等等均会采用默认值,也就是 LANG的值,也就是LC_COLLATE=LC_MESSAGES=……= LC_PAPER=LANG=zh_CN.UTF-8。
所以,locale是这样设定的:
1、如果你需要一个纯中文的系统的话,设定LC_ALL= zh_CN.XXXX,或者LANG=zh_CN.XXXX都可以,当然你可以两个都设定,但正如上面所讲,LC_ALL的值将覆盖所有其他的locale设定,不要作无用功。
2、如果你只想要一个可以输入中文的环境,而保持菜单、标题,系统信息等等为英文界面,那么只需要设定 LC_CTYPE=zh_CN.XXXX,LANG=en_US.XXXX就可以了。这样LC_CTYPE=zh_CN.XXXX,而LC_COLLATE=LC_MESSAGES=……= LC_PAPER=LANG=en_US.XXXX。
3、假如你高兴的话,可以把12个LC_*一一设定成你需要的值,打造一个古灵精怪的系统: LC_CTYPE=zh_CN.GBK/GBK(使用中文编码内码GBK字符集); LC_NUMERIC=en_GB.ISO-8859-1(使用大不列颠的数字系统) [email protected](德国的度量衡使用ISO-8859-15字符集) 罗马的地址书写方式,美国的纸张设定……。估计没人这么干吧。
4、假如你什么也不做的话,也就是LC_ALL,LANG和LC_*均不指定特定值的话,系统将采用POSIX作为lcoale,也就是 C locale。
也就是说如果没有设置这些环境变量的时候,在系统安装好的时候这些环境变量是有默认值的,默认值是POSIX。(这应该只针对英文系统,装中文系统的话,这些变量的默认值应该不是POSIX了。)
http://pubs.opengroup.org/onlinepubs/007908799/xbd/locale.html
http://pubs.opengroup.org/onlinepubs/007908799/xbd/locale.html#tag_005_002
这有Locale和POSIX locale的说明,有兴趣自己研究一下吧。
我的理解是,locale就相当于一个编码字符集,POSIX字符集里没有中文编码,所有如果使用POSIX编码的字符集去打开中文文件的话,就会出现乱码。
另外LANG和LANGUAGE有什么区别呢?
LANG – Specifies the default locale for all unset locale variables
LANGUAGE – Most programs use this for the language of its interface
LANGUAGE是应用程序中的设置语言的选项。而LANG是优先级很低的一个全局变量,它指定所有与locale有关的变量的默认值。
locale基本命令
### 查看系统默认的语言设置 [root@toy ~]# locale ### 查看所有语言 [root@room9pc01 ~]# locale -a ### 或者 查看系统支持的汉语区域语言 [root@toy ~]# localectl list-locales| grep zh ### 查看当前区域配置 [root@toy ~]# localectl status System Locale: LANG=zh_CN.utf8 VC Keymap: cn X11 Layout: cn ### 设置区域语言,其实在 /etc/locale.conf 在这个文本文件中,默认就一行 LANG=en_US.UTF-8 [root@toy ~]# localectl set-locale LANG=zh_CN.utf8 ### 查看上一条命令设置好的区域语言, ### 注意 centos6 是这个文件 /etc/sysconfig/i18n ,centos7 是 /etc/locale.conf [root@toy ~]# cat /etc/locale.conf LANG=zh_CN.utf8 ### 刷新bash 或者重启,使设置生效 ###
locale问题分析
1、根据优先级:先找LC_ALL的配置,发现没有,就开始找 LC_CTYPE 。
2、然后 LC_CTYPE=UTF-8 ,在centos中找不到这个配置项,所以报错。
### 可以通过locale -a查看到系统支持的语系, [root@localhost ~]# locale -a aa_DJ aa_DJ.iso88591 aa_DJ.utf8 aa_ER aa_ER@saaho aa_ER.utf8 aa_ER.utf8@saaho aa_ET 。。。 。。 。
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
这边两行的错误其实就是说LC_CTYPE这个编码文件找不到,然后LC_ALL也找不到。
3、因为前面两个都报错,所以默认就使用LANG的配置。
4、然后我们知道 /etc/sysconfig/i18n 和 /etc/sysconfig/i18n 中,都只设置了 LANG 变量,且系统连接时 LC_CTYPE 会将本机系统的值传递到远程主机的系统中。【LC_CTYPE 好像没有 设置过,应该是系统默认值】
locale问题解决方案
1、远程主机自己指定 LC_CTYPE 。在远程主机的本地化文件中添加 LC_CTYPE 的值,此优先级比客户端主机传递过来的值要高。
centos6下面全局语系的配置放在/etc/sysconfig/i18n文件,修改 $ vim /etc/sysconfig/i18n 增加 LC_CTYPE="en_US.UTF-8" 重启服务器,问题就解决了。 不过Centos7上没有/etc/sysconfig/i18n, 查了下有 /etc/locale.conf 文件起到同样的作用。 于是添加 LC_CTYPE="en_US.UTF-8" 重启服务器,问题就解决了。
2、取消客户端传递过来的 LC_CTYPE
在客户端编辑 vim /etc/ssh/ssh_config
找到SendEnv LANG LC_*
注释掉
3、修改客户端的 LC_CTYPE ,使得 LC_CTYPE= en_US.UTF-8,这样传递给远程主机时就能识别了。
4、在远程主机中,创建一个 UTF-8 的locale文件,这样子系统就能识别了,也就是可以找到该文件了。
举例: 编辑 /etc/locale.gen文件,反注释 en_US.UTF-8 UTF-8 一行. 执行生成命令 locale-gen 【locale-gen 好像在Ubuntu下可以,centos中没有这个命令】 http://manpages.ubuntu.com/manpages/bionic/man8/locale-gen.8.html
参考:
https://www.cloudbility.com/club/7195.html
https://www.jianshu.com/p/fb6c5d747700
https://www.jianshu.com/p/2b24861be987
https://blog.csdn.net/lemontree1945/article/details/80088986
https://www.cnblogs.com/xlmeng1988/archive/2013/01/16/locale.html
https://www.jianshu.com/p/2b24861be987