centos7初装系统-ssh登录locale编码问题

勘误,之前这篇文章有错误    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

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments