bash-4.4
研究题目: bash中有时候输入的汉字不能显示,或者有的是显示了,但是不能使用光标,光标走过汉字时,汉字就坏了。
相关文章: bash 中文汉字乱码问题
前面的研究文章中提到,当正确的设置了LANG编码时,bash是可以正确处理汉字的,但是,今天遇到的情况是,bash进程的环境变量LANG=zh_CN.UTF-8 是没问题的,但是,依然不能正确处理汉字,而且不是能显示汉字,光标走过汉字时,汉字坏掉;而是,汉字根本就不显示,strace结果如下:
我输入的是’汉’字,读入到第二个字节的时候,发现不对了,往标准错误写了一些错误消息,这个错误消息从源码上来看,是通过 _rl_arg_getchar() 输出的。
正常来讲,bash是停留在 下面代码处等待输入的:
从函数名可知(实际调试也是如此),该函数只读取一个字节,对于多字节字符来讲,该函数执行多次,正常来讲,多字节字符被完全读入之前,是不会被回显的,至于该多字节字符由几个字节组成的,这个问题不是该函数来处理的,而是用函数: rl_insert() 来处理的。
正常情况下等待输入时的调用栈如下;
当readline_internal_char通过rl_read_key -> rl_getc 读到一个字节时,就将该字节交给_rl_dispatch -> _rl_dispatch_subseq 来处理,当前如果处于bash的插入模式,则交由rl_insert 函数来处理,如下:
每次read一个字符是函数 readline_internal_char() 发起的,但是,具体需要读入几个字节算一个字符,是函数rl_insert() 中判断的,并根据判断结果来调用适当次数的rl_read_key()函数。而rl_insert函数也是bash在insert模式下调用的函数,(如果是替换模式就是函数_rl_overwrite_char()了 ?)。
rl_insert 中调用了 _rl_insert_char() 可以判断还有几个字节需要读入。
从MB_LEN_MAX 常量来看,多字节字符最少支持16字节的字符的。
bash编译时,需要定义 HANDLE_MULTIBYTE 常量,才能支持多字节的,如何判断bash是否支持多字节呢?
strings /bin/bash |grep _rl_read_mbstring
如果存在该字符串,基本就算是支持了,因为该函数在 #if defined (HANDLE_MULTIBYTE) 中定义的;然而,真正本次讨论的问题,和该函数并无关系。
关于多字节的很多逻辑都在下面文件中:
当需要读入一个完整的多字节时,将多字节的内容缓存到pending_bytes数组中,用pending_bytes_length 来记录已读入字节的长度,通过函数 mbrtowc 来判断输入字符是否完整,该函数并不属于bash,(至此,似乎和bash本身没啥关系了)。
参考: man mbrtowc ;该man页中最下面有个NOTE:
The behavior of mbrtowc() depends on the LC_CTYPE category of the current locale.
然后,我们试试:
# export LC_CTYPE=zh_CN.UTF-8 bash: warning: setlocale: LC_CTYPE: cannot change locale (zh_CN.UTF-8)
参考: https://www.cnblogs.com/kevingrace/p/8191929.html
因为我使用的是ubuntu容器,里面没有中文相关软件包,locale -a查看如下:
如果仅仅是为了让bash能正确处理汉字,其实,设置正确的编码已经足够,如上图:
export LC_CTYPE=C.UTF-8
或
export LC_ALL=C.UTF-8
至于如何才能正确支持 LC_CTYPE=zh_CN.UTF-8 或者 LC_CTYPE=en_US.UTF-8 ,稍后研究
看来LC_ALL不是一个简单的变量,不管export与否,bash都知道这是一个需要特殊处理的变量。虽然该变量的设置是能被bash察觉的,但是依然不能影响当前bash的编码。
虽然这里看似设置错误了,实际上,变量赋值时成功的:
网友评论已有0条评论, 我也要评论