博主头像
mxd's Blog

以技术为翼,以生活为魂

终端里的 ^[[200~ 和 ^[[A 是什么

不知道大家有没有遇到过这种情况。
明明只是想执行一条很普通的命令,结果粘贴进去以后变成了这样:
# ^[[200~ldd $(which nginx) | grep ssl~
-bash: $'\E[200~ldd': command not found

又或者,在某些奇奇怪怪的环境里,按一下方向键准备调出上一条历史命令,终端里却出现:

^[[A

第一次看到这种东西的时候,多少会有点懵。

这玩意儿是什么?终端中毒了?SSH 连坏了?还是 Bash 抽风?

前段时间我在浏览器和 Xshell 之间来回复制命令时,又一次遇到了这个问题。以前见过,但一直停留在“重开一个终端就好了”的阶段。这次正好有空,就顺手把原理翻了一遍。

后来发现,其实这两种现象本质上是一回事:控制序列被当成普通文本显示出来了

很多人以为终端只是“输入字符、显示字符”的黑框。但实际上,终端协议里有大量特殊字符负责控制行为。

比如方向键。

当你按下上方向键的时候,发送给程序的并不是“上”这个概念,而是一串字节:

ESC [ A

如果显示出来,大概就是:

^[[A

其中:

  • ^[ 表示 ESC(0x1B)
  • [ 是左方括号
  • A 表示上方向键

正常情况下,Bash、Zsh 这些 Shell 会识别它:

“哦,用户按了上方向键,去取历史命令。”

于是你看到的是上一条命令。

但如果中间某个环节没识别这串控制字符,比如:

  • TERM 设置不对;
  • readline 配置异常;
  • SSH 客户端兼容性有问题;
  • 程序本身没启用行编辑;

那么它就会被原样打印出来:

^[[A

于是你会觉得方向键失灵了。

^[[200~ 则更有意思。

它对应的是一种叫做 Bracketed Paste Mode(括号粘贴模式) 的机制。

名字挺唬人,其实目的很朴素:让终端知道,“接下来这段内容不是用户一个字一个字敲出来的,而是一次粘贴操作”。

开始粘贴时:

ESC [ 200 ~

结束粘贴时:

ESC [ 201 ~

也就是:

^[[200~
……
^[[201~

正常情况下,Shell 收到以后会进入“粘贴模式”。

这样做有不少好处。

比如有些多行命令、自动缩进、自动补全,在粘贴时不应该被干扰。Shell 知道这是粘贴,就不会像处理键盘输入那样逐字符处理。

问题在于,如果 SSH 客户端、终端模拟器、Shell 三者中有一个没配合好,这些本来应该被隐藏的控制序列,就会直接出现在命令前面。

于是就变成了:

^[[200~ldd $(which nginx) | grep ssl

Bash 看了一眼:

“什么鬼命令?”

然后一本正经地告诉你:

-bash: $'\E[200~ldd': command not found

我自己的情况,大概率是浏览器复制内容到 Xshell 时触发的。

尤其是一些老版本 Xshell,对 Bracketed Paste 的支持并不算完美。有时候复制 ChatGPT 给出的命令,或者网页上的代码块,就会莫名其妙多出这一串东西。

发现规律以后,反倒没那么紧张了。

看到:

^[[200~

我知道是粘贴模式出了问题。

看到:

^[[A

我知道是方向键控制序列没被解释。

它们并不是什么“乱码”,只是 ANSI Escape Sequence 被人类看见了而已。

如果经常遇到,可以试试升级 SSH 客户端,或者检查一下终端设置里是否开启了 Bracketed Paste。Bash 用户也可以看看:

bind -V | grep bracket

有些系统里默认关闭了相关支持。

当然,大多数时候最有效的解决办法依然是:关掉当前 SSH 会话,重新连一次。

虽然这个操作听起来毫无技术含量,但不得不承认,是最有用的,也是最不用去折腾那么多的。

以前看到这些字符,总觉得像是什么神秘代码。

现在再看到它们,脑子里的第一反应已经变成了:

“哦,原来是控制序列漏出来了。”

终端用了这么多年,很多习以为常的东西,其实都是各种约定、兼容和历史包袱叠加出来的结果。平时一切正常的时候感觉不到,一旦某个环节没接住,这些藏在背后的细节就会突然跳到台前,提醒你:所谓的“黑框”,远比想象中热闹。

终端里的 ^[[200~ 和 ^[[A 是什么
https://blog.mxdyeah.com/post/strange-terminal-characters
本文作者 mxdyeah
发布时间 2026-06-13
许可协议 CC BY-NC-SA 4.0
发表新评论

AD: