一、前言
Xshell跟Gnome Terminal相比,两者都是终端模拟器(在Xshell中也可以执行简单的内置命令,如“cd”,“ls”等),地位相同。
二、原理分析
涉及到乱码,那么需要了解编码解码过程。在终端模拟器中执行命令,通信过程示意图如图1所示。
图1
在以上通信过程中,在“命令执行单元”处发生了一系列的编码解码过程,在“终端模拟器”处也发生了一系列的编码解码过程,此外,我们常常创建SSH连接,从而建立一个远端Shell会话,在该情景中,通信过程示意图如图2所示,由图2可知,在该情景中,跟原来的通信过程相比,只不过“命令执行单元”处与“终端模拟器”处之间的通信数据经过SSH安全通道而已,一般并不影响整体的编码解码过程。
图2
“命令执行单元”处执行命令过程中会发生一系列的编码解码过程,不同命令具有不同实现,因而不同命令执行过程中发生的编码解码过程也不尽相同(以下这些链接中的内容可作为该结论的证据:《使用vi和less查看文本出现中文乱码,使用cat正常》,《查看日志文件more正常,用less查看出现乱码》)。另外,很多命令在执行过程中会去读取locale系列环境变量(比如“LANG”,“LANGUAGE”,“LC_ALL”,“LC_CTYPE”等)的配置值用于编码解码过程。
比如“uniq”命令会去使用“LC_COLLATE”等环境变量的配置值,“grep”命令会去使用“LC_ALL”等环境变量的配置值,“vim”命令会去使用“LC_CTYPE”等环境变量的配置值。
“终端模拟器”处执行命令过程中也会发生一系列的编码解码过程,主要有3方面内容:
1、配置终端模拟器使用的编码方案,对于Gnome Terminal,在图3所示位置进行配置,对于Xshell,在图4所示位置进行配置,对于Xftp,在图5所示位置进行配置
2、执行命令时,使用终端模拟器配置的编码方案,对原命令字符串进行编码,将得到的字节流传递给“命令执行单元”
3、展现命令执行结果时,获取字节流形式的命令执行结果,使用终端模拟器配置的编码方案,对其进行解码,得到字符串形式的命令执行结果
图3
图4
图5
三、实验
3.1、ls命令
3.1.1、实验1
现有一个名为“你好吗.txt”的文件,相应于该文件名的存储内容存储的是使用“UTF-8”编码方案编码得到的字节流。
设置不同的locale系列环境变量配置值和终端模拟器编码方案,得到不同的“ls命令”执行结果,具体如表1。
表1
locale系列环境变量配置值 | 终端模拟器(实验了Gnome Terminal和Xshell)编码方案 | ls命令执行结果截图 |
---|---|---|
zh_CN.utf8 | UTF-8 | |
zh_CN.gbk | UTF-8 | |
zh_CN.utf8 | GBK | |
zh_CN.gbk | GBK |
3.1.2、实验2
现有一个名为“你好吗.txt”的文件,相应于该文件名的存储内容存储的是使用“GBK”编码方案编码得到的字节流。
设置不同的locale系列环境变量配置值和终端模拟器编码方案,得到不同的“ls命令”执行结果,具体如表2。
表2
locale系列环境变量配置值 | 终端模拟器(实验了Gnome Terminal和Xshell)编码方案 | ls命令执行结果截图 |
---|---|---|
zh_CN.utf8 | UTF-8 | |
zh_CN.gbk | UTF-8 | |
zh_CN.utf8 | GBK | |
zh_CN.gbk | GBK |
3.2、vim命令
3.2.1、实验1
现有一个名为“a.txt”的文件,存储有内容“你好吗?”,使用的编码格式为“UTF-8”。
设置不同的locale系列环境变量配置值和终端模拟器编码方案,得到不同的“vim a.txt”执行结果,具体如表3。
表3
locale系列环境变量配置值(跟“3.1、ls命令”一样,也是将locale系列中的所有环境变量的配置值设为同一个值) | 终端模拟器(实验了Gnome Terminal和Xshell)编码方案 | “vim a.txt”命令执行结果截图 | VIM环境中执行“:e ++enc=utf8”结果截图 |
---|---|---|---|
zh_CN.utf8 | UTF-8 | ||
zh_CN.gbk | UTF-8 | ||
zh_CN.utf8 | GBK | ||
zh_CN.gbk | GBK |
3.2.2、实验2
现有一个名为“a.txt”的文件,存储有内容“你好吗?”,使用的编码格式为“GBK”。
设置不同的locale系列环境变量配置值和终端模拟器编码方案,得到不同的“vim a.txt”执行结果,具体如表4。
表4
locale系列环境变量配置值(跟“3.1、ls命令”一样,也是将locale系列中的所有环境变量的配置值设为同一个值) | 终端模拟器(实验了Gnome Terminal和Xshell)编码方案 | “vim a.txt”命令执行结果截图 | VIM环境中执行“:e ++enc=gbk”结果截图 |
---|---|---|---|
zh_CN.utf8 | UTF-8 | ||
zh_CN.gbk | UTF-8 | ||
zh_CN.utf8 | GBK | ||
zh_CN.gbk | GBK |
四、其他
4.1、locale系列环境变量
在以上实验中,locale系列中的所有环境变量的配置值都被设为“zh_CN.gbk”或者“zh_CN.utf8”,其实“ls命令实现”或者“vim命令实现”只需要读取locale系列中特定的部分的环境变量的配置值即可,locale系列中其他的环境变量的配置值并不会影响“ls命令”或者“vim命令”的运行。只不过我们并不知道上述提及的“locale系列中特定的部分的环境变量”是哪些,故而为了简单起见,将locale系列中的所有环境变量的配置值都设为“zh_CN.gbk”或者“zh_CN.utf8”。
4.2、推测vim命令读取文件内容发生的主要的编码解码过程
由“3.2、vim命令”中的实验可推知,使用vim命令读取文件内容中发生的主要的编码解码过程如下:读取文件内容的字节流,使用locale系列环境变量指定的编码方案(也可以通过“:e ++enc=?”命令自己指定要使用的编码方案)对字节流进行解码得到文件内容的字符流,再使用locale系列环境变量指定的编码方案对获得的字符流进行编码得到字节流,将前述编码得到的字节流传递给终端模拟器。
因而,只要locale系列环境变量指定的编码方案跟终端模拟器使用的编码方案一致,那么直接可以得到文件内容的非乱码展现或者通过“:e ++enc=?”命令得到文件内容的非乱码展现。
4.3、实验中用到的两个脚本
脚本1:
#!/bin/bash
cd /home/dsl/tmp/shell
export LC_ALL=$1
export LANG=$1
export LANGUAGE=$1
locale
echo "---------"
echo "---------"
echo "---------"
ls
脚本2:
#!/bin/bash
cd /home/dsl/tmp/shell
export LC_ALL=$1
export LANG=$1
export LANGUAGE=$1
locale
echo "---------"
echo "---------"
echo "---------"
vim a.txt