最近在学正则表达式,接触到POSIX 字符集,这个传统的字符区域的优点体现在其在处理快速地指定字符集合的问题方面易于理解并且有效。但是这里我要告诉大家关于它的一个小知识。首先,我们看看通配符怎样被用来完成路径名展开操作。我们知道在某种程度上,字符区域被使用的方式几乎与在正则表达式中的用法一样,但是有一个问题:
jeremy@ubuntu:/tmp$ ls /usr/sbin/[ABCDEFGHIJKLMNOPQRSTUVWXYZ]*
/usr/sbin/ModemManager /usr/sbin/NetworkManager
这个命令产生了期望的结果即只有以大写字母开头的文件名,但是:
jeremy@ubuntu:/tmp$ ls /usr/sbin/[A-Z]*
/usr/sbin/bccmd /usr/sbin/pm-hibernate
/usr/sbin/biosdecode /usr/sbin/pm-powersave
/usr/sbin/bluetoothd /usr/sbin/pm-suspend
/usr/sbin/chat /usr/sbin/pm-suspend-hybrid
/usr/sbin/chgpasswd /usr/sbin/popcon-largest-unused
/usr/sbin/chpasswd /usr/sbin/popularity-contest
/usr/sbin/chroot /usr/sbin/pppconfig
/usr/sbin/cpgr /usr/sbin/pppd
/usr/sbin/cppw /usr/sbin/pppdump
/usr/sbin/cracklib-check /usr/sbin/pppoeconf
/usr/sbin/cracklib-format /usr/sbin/pppoe-discovery
/usr/sbin/cracklib-packer /usr/sbin/pppstats
通过这个命令我们得到整个不同的结果,(输出了一大堆,只显示了一部分结果列表)。为什么会是那样?
这就要追溯到 Unix 刚刚开发的时候,它只知道 ASCII 字符,并且这个特性反映了事实。在 ASCII中,前 32 个字符(数字 0 - 31)都是控制码(如 tabs,backspaces,和回车)。随后的 32 个字符(32 - 63)包含可打印的字符,包括大多数的标点符号和数字 0 到 9。再随后的 32 个字符(64 - 95)包含大写字符和一些更多的标点符号。最后的31 个字符(96 - 127)包含小写字母和更多的标点符号。基于这种安排方式,系统使用这种排序规则的ASCII:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
这个不同于正常的字典顺序,其像这样:
aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ
随着 Unix 系统的知名度在美国之外的国家传播开来,就需要支持不在 U.S. 英语范围内的字符。于是就扩展了这个 ASCII 字符表,使用了整个 8 位,添加了字符(数字 128 - 255),这样就容纳了更多的语言。为了支持这种能力,POSIX 标准介绍了一种叫做 locale 的概念,其可以被调整,来为某个特殊的区域,选择所需的字符集,即系统的语言设置。通过这个设置,POSIX 相容的应用程序将会使用字典排列顺序而不是 ASCII 顺序。这就解释了上述命令的行为。当 [A-Z] 字符区域按照字典顺序解释的时候,包含除了小写字母“a”之外的所有字母,因此得到这样的结果。