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

Ell*_*t B 17 terminal-emulator character-encoding centos macos

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

!@#$%^&*()_+{}
Run Code Online (Sandbox Code Playgroud)

当我打开这个vi或者nano它看起来正如我上面写的是正确的。但在终端中它看起来像这样:

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

$ od -An -vtx1 < chars.txt
 21 40 23 24 25 5e 26 2a 28 29 5f 2b 7b 7d 0a
Run Code Online (Sandbox Code Playgroud)

这些奇怪的字符随处可见,即使在我打字时也是如此。这台机器一直工作到今天。我认为这是在我下载了一个二进制文件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=
Run Code Online (Sandbox Code Playgroud)

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

Sté*_*las 60

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

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

在哪里:

其他人撤消设置。

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

至于为什么nano例如正常显示它们,您会发现,如果您nanoscript命令会话中运行并typescript随后查看结果,nano\e(B在切换到备用屏幕\e[?1049h可能会发送一个序列(为 G0 选择 US-ASCII)作为某些 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
[...]
Run Code Online (Sandbox Code Playgroud)

例如。

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

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

正如你指出你的工作站正在运行MacOS和不CentOS的,需要注意的是MacOS的似乎与更老版本的现身xterm269如2021年),和我期望Terminal.app你明确你实际使用的终端仿真器具有相同的错误是xterm使用拥有(因为它没有正确模拟 VT220 终端,尽管它的目的可能是模拟那些旧版本xterm)。

在更老的天(直到xterm的182即转变我相信)倾销二进制文件到终端的时候,另一种常见的人工制品被切换到特殊字符和线条设置时为0x0E字节(SO/^N控制字符)被送往终端。SO仍然切换到 G1 集,但当时 G1 集被初始化为线图集。通过发送\e(0选择G0的线图集的序列,您今天可以获得相同的效果(尽管它不太可能发生在随机二进制文件中):

$ printf '\e(0 blahblah \e(B\n'
 ????????
Run Code Online (Sandbox Code Playgroud)

您可以回到旧的行为,其中^N/^O在 ASCII 和带有序列的线条图集之间切换\e)0

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

更多信息请访问:

  • 我希望我对这种质量的答案有第二次投票。谢谢你。 (4认同)