为什么 {} 在 Terminal.app 中开始显示为 äå?

为什么 {} 在 Terminal.app 中开始显示为 äå?

我正在运行 CentOS 7.9,今天我的终端显示奇怪的字符。有些字母看起来不错,但有些符号显示为一些非英语字符。例如,我制作了一个包含以下内容的文本文件:

!@#$%^&*()_+{}

当我打开它时vinano它看起来是正确的,就像我上面写的那样。但在终端中它看起来像这样:

$ cat chars.txt 
!É#$%Ü&*()_+äå

$ od -An -vtx1 < chars.txt
 21 40 23 24 25 5e 26 2a 28 29 5f 2b 7b 7d 0a

这些奇怪的字符无处不在,甚至在我打字时也是如此。这台机器直到今天都运转良好。我思考它发生在我下载了一个二进制文件curl并忘记使用该-O参数之后。重新启动并以其他用户身份登录没有帮助。我的区域设置如下;我不知道还要寻找什么。我使用的 shell 是 Bash 版本 4.2,没有什么异常。

$ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

编辑:更准确的说法是服务器的 shell 是 bash 4.2。我在 macOS Big Sur 上使用 Terminal.app 登录。

答案1

如果我这样做,我可以使用xterm终端模拟器(版本 366)重现它:

$ printf '\e[?42h\e(H'; cat chars.txt; printf '\e(B\e[?42l'
!É#$%Ü&*()_+äå

在哪里:

其他的则撤消设置。

要将终端恢复到正常状态,还可以使用 ncursesreset命令。在这里,我发现它\ec发送的序列(例如发送的rs1/功能)负责恢复默认字符集)。reset_1stringtput rs1

至于为什么nano正常显示它们,您会发现如果您在命令会话nano中运行并随后script查看结果,那么在切换到命令会话后确实会发送一个序列(为 G0 选择 US-ASCII)typescriptnano\e(B备用屏幕大概是\e[?1049h一些 ncurses 初始化的一部分,当nano退出时离开备用屏幕时,原始字符集将被恢复。

现在,\e(H偶然在二进制文件中获得一个序列(0x1b 0x28 0x48 字节序列)是合理的。平均而言,1600 万个随机 3 字节序列中就有一个是这样的。在这里,我找到了一些:

$ LC_ALL=C grep -rFl $'\e(H' /lib
/lib/x86_64-linux-gnu/libicui18n.so.66.1
/lib/x86_64-linux-gnu/ceph/libceph-common.so.2
[...]

例如。

\e[?42h偶然发现 6 字节(48 位)序列的可能性要小得多(280 万亿个 6 字节序列中就有 1 个)。更重要的是,\e(H在您转储到终端的随机二进制文件中按顺序同时拥有这两个文件。

xterm在CentOS7上是旧版本(295)。在该版本中,\e[?42h不需要启用 ISO2022 处理的序列。在该版本中xterm\e(H仅凭 , 就足以获得该行为。那改变了在版本 297 中2013 年 9 月发布。这解释了为什么它在 CentOS7 或那个时代的任何系统中比在较新的系统中更有可能遇到这种情况。

正如您所指出的,您的工作站运行的是 macos 而不是 CentOS,请注意,macos 似乎附带了更旧版本的xterm(269截至 2021 年),我希望您澄清您实际使用的终端模拟器具有与过去Terminal.app相同的错误(因为它没有正确模拟 VT220 终端,尽管它的目的可能是模拟那些旧版本)。xtermxterm

在更古老的日子里(直到xterm 182我相信它被更改了),将二进制文件转储到终端时的另一个常见问题是切换到特殊字符和线条图集当 0x0e 字节(SO/^N控制字符)发送到终端时。SO仍然切换到 G1 集,但在 G1 集被初始化为线条图集。今天,通过发送序列(\e(0选择线条图集对于 G0:

$ printf '\e(0 blahblah \e(B\n'
 ␉┌▒␤␉┌▒␤

您可以回到原来的行为,其中^N/^O在 ASCII 和线条图集\e)0顺序。

至于为什么重新启动没有帮助,请记住,是您的终端模拟器受到了转义序列的影响。重新启动您从终端仿真器进入的系统ssh不会有帮助。重新启动您运行的系统xterm会有帮助,但是也可以重新启动该终端仿真器,或者reset在终端中运行上面所示的命令(本地或通过ssh,只要将rs1转义序列发送到终端模拟器)。

更多信息请访问:

相关内容