在Ubuntu18.04版本中,编写一个“判断输入字母大小写”的shell脚本,如下:
请问20.04版本修复了什么地方,导致脚本不添加LC_ALL=C也可以正确地运行?
接下来输入不同字母判断程序正确性:
可以发现大小写判断是错误的,原因是因为使用了中国地区的语言环境:
这时候在代码中加入LC_ALL=C改变语言环境为C即可正确判断,新脚本:
新结果:
在Ubuntu新版本20.04中,我依然是中国地区语言环境,但该脚本不需要添加LC_ALL=C也可以正确判断字母的大小写。关于18.04与20.04版本差异的问题(shell判断输入字母大小写)
-
- 帖子: 2
- 注册时间: 2020-12-16 12:48
- 系统: Windows
- astolia
- 论坛版主
- 帖子: 6454
- 注册时间: 2008-09-18 13:11
Re: 关于18.04与20.04版本差异的问题(shell判断输入字母大小写)
很好的问题。要找罪魁祸首的话,是glibc库。
bash在处理[x-y]这种东西时,做范围判断用的是c库函数strcoll,而strcoll做字符串比较时,会受到LC_COLLATE环境变量的影响,根据LC_COLLATE定义的语言来决定字符的顺序。
LC_COLLATE只设置了语言,在指定语言中各个字符的具体顺序,是存在另外的文件中的。以zh_CN为例,strcoll在比较时,会去检查/usr/share/i18n/locale/zh_CN中LC_COLLATE和END LC_COLLATE之间的定义。可以看到里面是句copy "iso14651_t1_pinyin",也就是和同目录下iso14651_t1_pinyin文件中定义的内容一样。同样地,iso14651_t1_pinyin又参照了iso14651_t1_common的内容。而正是iso14651_t1_common在18.04和20.04中的不同导致了你的问题。
你在18.04的iso14651_t1_common文件中,可以找到这样的一段正是这些定义语句,把事情搞砸了。
collating-symbol在这里的意思是把后面的字符组视为同一个顺序号。<a>组里包括了小写的a和大写的A,还有些其他a的变体,比如à。strcoll在做比较时,就会把a、A、à这些都视为相同的东西。这样一来,a自然也在[A-Z]的范围里了。
当你设置LC_ALL=C时,LC_COLLATE也一并设置为了C,/usr/share/i18n/locale/C里LC_COLLATE段定义的顺序,就是字符的unicode编码,所以strcoll就会认为a和A是不同的东西,a就不会在[A-Z]的范围里。
18.04里glibc的版本是2.27,20.04里glibc的版本是2.31,这个问题是在glibc 2.28里修正的。具体可见2.28发布日志Major new features的第一条 https://sourceware.org/legacy-ml/libc-a ... 00002.html
bash在处理[x-y]这种东西时,做范围判断用的是c库函数strcoll,而strcoll做字符串比较时,会受到LC_COLLATE环境变量的影响,根据LC_COLLATE定义的语言来决定字符的顺序。
LC_COLLATE只设置了语言,在指定语言中各个字符的具体顺序,是存在另外的文件中的。以zh_CN为例,strcoll在比较时,会去检查/usr/share/i18n/locale/zh_CN中LC_COLLATE和END LC_COLLATE之间的定义。可以看到里面是句copy "iso14651_t1_pinyin",也就是和同目录下iso14651_t1_pinyin文件中定义的内容一样。同样地,iso14651_t1_pinyin又参照了iso14651_t1_common的内容。而正是iso14651_t1_common在18.04和20.04中的不同导致了你的问题。
你在18.04的iso14651_t1_common文件中,可以找到这样的一段
代码: 全选
collating-symbol <a>
collating-symbol <b>
collating-symbol <c>
...
collating-symbol在这里的意思是把后面的字符组视为同一个顺序号。<a>组里包括了小写的a和大写的A,还有些其他a的变体,比如à。strcoll在做比较时,就会把a、A、à这些都视为相同的东西。这样一来,a自然也在[A-Z]的范围里了。
当你设置LC_ALL=C时,LC_COLLATE也一并设置为了C,/usr/share/i18n/locale/C里LC_COLLATE段定义的顺序,就是字符的unicode编码,所以strcoll就会认为a和A是不同的东西,a就不会在[A-Z]的范围里。
18.04里glibc的版本是2.27,20.04里glibc的版本是2.31,这个问题是在glibc 2.28里修正的。具体可见2.28发布日志Major new features的第一条 https://sourceware.org/legacy-ml/libc-a ... 00002.html
-
- 帖子: 2
- 注册时间: 2020-12-16 12:48
- 系统: Windows
Re: 关于18.04与20.04版本差异的问题(shell判断输入字母大小写)
原来是这样!非常感谢。astolia 写了: ↑2020-12-17 13:21 很好的问题。要找罪魁祸首的话,是glibc库。
bash在处理[x-y]这种东西时,做范围判断用的是c库函数strcoll,而strcoll做字符串比较时,会受到LC_COLLATE环境变量的影响,根据LC_COLLATE定义的语言来决定字符的顺序。
LC_COLLATE只设置了语言,在指定语言中各个字符的具体顺序,是存在另外的文件中的。以zh_CN为例,strcoll在比较时,会去检查/usr/share/i18n/locale/zh_CN中LC_COLLATE和END LC_COLLATE之间的定义。可以看到里面是句copy "iso14651_t1_pinyin",也就是和同目录下iso14651_t1_pinyin文件中定义的内容一样。同样地,iso14651_t1_pinyin又参照了iso14651_t1_common的内容。而正是iso14651_t1_common在18.04和20.04中的不同导致了你的问题。
你在18.04的iso14651_t1_common文件中,可以找到这样的一段正是这些定义语句,把事情搞砸了。代码: 全选
collating-symbol <a> collating-symbol <b> collating-symbol <c> ...
collating-symbol在这里的意思是把后面的字符组视为同一个顺序号。<a>组里包括了小写的a和大写的A,还有些其他a的变体,比如à。strcoll在做比较时,就会把a、A、à这些都视为相同的东西。这样一来,a自然也在[A-Z]的范围里了。
当你设置LC_ALL=C时,LC_COLLATE也一并设置为了C,/usr/share/i18n/locale/C里LC_COLLATE段定义的顺序,就是字符的unicode编码,所以strcoll就会认为a和A是不同的东西,a就不会在[A-Z]的范围里。
18.04里glibc的版本是2.27,20.04里glibc的版本是2.31,这个问题是在glibc 2.28里修正的。具体可见2.28发布日志Major new features的第一条 https://sourceware.org/legacy-ml/libc-a ... 00002.html