在\u
有效的 shell(bash +4.3、ksh93 或 zsh)中,我们可以打印 Unicode 字符:
$ printf 'a b c \ua0 \ua1 \ua2 \ua3 \n'
a b c ¡ ¢ £
这是来自Latin-1_Supplement范围的一些字符。
但是,一旦9f
添加了 Unicode 字符,打印就会停止,直到 Unicode9c
被打印出来。
\u9f
和\u9c
(APC 和 ST) 都是控制C1
字符。
$ printf 'a b c \u9f d e f \u9c \ua0 \ua1 \ua2 \ua3 \n'
a b c ¡ ¢ £
字符 def 消失。
可以肯定的是,它printf
正在生成所有字符,并且将输出重定向到其他一些软件(而不是终端)将显示生成的字符:
$ printf 'a b c \u9f d e f \u9c \ua0 \ua1 \ua2 \ua3 \n' | od -A n -tx1
61 20 62 20 63 20 c2 9f 20 64 20 65 20 66 20 c2
9c 20 c2 a0 20 c2 a1 20 c2 a2 20 c2 a3 20 0a
这足以证明正在生成字符。那么,为什么它们没有被打印(显示有一些可见的字形)?
我的问题是:
- 实际上是
APC
连接到ST
。它在哪里定义? - 这两个字符之间的字符是否发送到某个应用程序?
- 如果是这样,适用于哪个应用程序?
- 谁负责这种重定向?外壳,终端或其他东西?
编辑
和终端都xterm
不会konsole
删除d e f
字符。
这证实这是终端应用程序的内部问题,而不是外壳。还没有找到定义的地方。
这些控制字符实际上并不是 Unicode 的原始字符,而是继承自旧的字符集规范,例如ECMA-48、ISO/IEC 6429 和 ISO/IEC-8859 系列字符编码。从广义上讲,这些标准在 C1 控制字符上基本上是相互一致的(因为它们相互向后兼容,甚至还兼容一些更旧的规范)。
由于 ISO/IEC 6429 的副本正在出售,我不希望在互联网上找到免费的合法副本,但 ECMA-48 说:
和:
Unicode 在 C1 控制字符范围内只定义了一个控制字符:U+0085 Next Line (NEL)。对于 C1 范围内的任何其他字符,规范的这一部分适用:
我无法在这里验证它,但我希望 ISO/IEC 6429 与 ECMA-48 所说的非常接近,如上所述。此外,终端的作者可能认为“向后兼容 pre-Unicode 7 位和 8 位字符编码,如 ECMA-48”是一种特定的应用程序用途。
因此,终端可能会合法地将 APC 和 ST 之间的字符解释为“我不知道这些是做什么用的,但我肯定知道这些不打算显示为常规输出。”
终端可能会或可能不会以某种方式对封装在 APC 和 ST 之间的特定字符串做出反应,并忽略任何不匹配的字符串。由于终端窗口是“人类之前的最后一步”,它当然可以假设任何到达它的应用程序命令字符串都是为了让终端解释和操作(如果适用),以及任何无法识别的此类字符串由终端必须是错误的。
显示“无效编码”字符或其他错误消息是不合适的,因为该字符串被有效地编码为“特定于应用程序的控制字符串,而不是用于显示”。因此,对于题为“角色要去哪里?”的问题的答案。最有可能:它们作为无效控制字符串的一部分被丢弃。
但请注意,Unicode 规范说“......可能被解释......”,而不是“......必须被解释......”。因此,其他终端实现选择只是将APC和ST字符作为没有适用意义的不可打印控制字符忽略也不一定是无效的。
Stack Overflow 上的这个问题还讨论了涉及 APC 和 ST 控制字符的控制序列。
那里接受的答案说:
这些字符没有被发送到任何地方,尽管它们在输出中,但它们根本没有被您的终端显示:
您还可以通过重定向到一个文件然后调查该文件来确认它们是否在输出中:
看起来终端对 和 的组合所做的事情
\u9f
取决于\u9c
实现。只是碰巧你的终端处理它的方式是向后移动几个字符并从那里继续打印,这会导致覆盖其他字符。这就是为什么您会看到:我可以在 上重现它
gnome-terminator
,但xterm
只打印一个空格:以下是屏幕截图中的相同内容:
这类似于在一个更明确的情况下发生的情况,即使用回车符(
\r
),其工作就是回到行首。这就是为什么你得到:终端开始打印
12345
,然后将其\r
发送回行的开头,在那里它用 覆盖了12345
,67890
所以您最终看到的只是67890
. 但是132345
没有发送到任何其他程序,它仍然存在,它根本不可见,因为其他字符已经覆盖了它:您正在解释输出 UTF8 字符序列的命令以及您在终端模拟器窗口(通常称为“我的终端窗口”)中看到的结果。
然后,您描述似乎不会导致在终端仿真器窗口中显示可见结果的字符序列。你问,“字符是否被发送到某个应用程序?”
是的,它们被传送到您的终端仿真器,它解释它接收到的字符序列并决定它将在其窗口中显示哪些字形供您查看。