ANSI转义序列

ANSI转义序列（ANSI escape sequences）是一种带内信号的转义序列标准，用于控制视频文本终端上的光标位置、颜色和其他选项。在文本中嵌入确定的字节序列，大部分以`ESC`转义字符和""字符开始，终端会把这些字节序列解释为相应的指令，而不是普通的字符编码。

ANSI序列是在二十世纪七十年代引入的标准，用以取代特定于终端供应商的序列，并在二十世纪八十年代早期开始在计算机设备市场上广泛使用。与早期缺少光标移动功能的系统相比，新生的电子公告板系统使用ANSI序列改进其显示。正是因为这个原因，ANSI序列变成了所有制造商共同采用的标准。

在21世纪，尽管硬件文本终端已经越来越少了，但ANSI标准依然存在，因为大多数终端模拟器会对部分ANSI转义序列进行解释。一个值得注意的例外是，在微软Windows 10更新TH2之前，Windows操作系统的Win32控制台是不支持ANSI转义序列的。

## 历史

最初，几乎每个视频终端制造商都各自添加了特定的转义序列用于执行一些特殊操作，比如把光标置于屏幕上的某个位置。举例来说，VT52终端允许通过发送`ESC`字符、`y`字符，后面跟上两个等于x,y位置的数值加上32的字符（这是为了从ASCII空格字符开始，并避开控制字符），将光标置于屏幕上的x,y位置。

由于这些序列对于不同的终端并不一样，因此人们不得不开发了一些复杂的库（比如termcap）和实用程序（比如tput），以便程序可以使用同一套API应对各种终端。另外，在很多终端中需要借助字符的二进制值发送数字（如行和列）。对于某些编程语言，以及内部不使用ASCII的系统来说，把数字转换为正确的字符常常是有困难的，甚至完全做不到。

ANSI标准试图解决这些问题。标准制订了一种所有终端共用的指令集，并要求用ASCII的数字字符传递所有数值信息。该系列的第一个标准是1976年通过的ECMA-48。它是一系列字符编码标准的延续，其中第一个是从1965年的ECMA-6，一个7位标准，ISO 646就源自此标准。“ANSI转义序列”的名称可以追溯到1979年ANSI采用ANSI X3.64。此外，ANSI X3L2委员会与ECMA委员会TC 1合作制订了一个几乎一模一样的标准。以上两个标准合并为ISO 6429的国际标准。1994年，ANSI取消了其标准，以支持国际标准。

第一个支持这个标准的流行视频终端是1978年推出的Digital VT100。这个终端在市场上非常成功，引发了各种各样的仿制品，其中最早和最流行的是1979年的Zenith Z-19。其他品牌还有Qume QVT-108，Televideo TVI-970，Wyse WY-99GT。另外，许多其他品牌的终端也不同程度地兼容可选的“VT100”、“VT103”或“ANSI”模式。随着越来越多的软件（尤其是BBS系统）普及，越来越多的软件依赖转义序列起作用，导致几乎所有新的终端和终端模拟器都支持了此标准。

1981年，ANSI X3.64被美国政府采用（FIPS 86）。后来，美国政府停止复制行业标准，所以FIPS 86又被撤回了。

ECMA-48已经经历了多次更新换代，目前是从1991年开始的第5版。它也被ISO和IEC用作标准ISO/IEC 6429。

## 平台支持

### 类Unix系统和AmigaOS

<image>

随着诸多BBS和线上服务广泛使用ANSI，到20世纪80年代中期，ANSI几乎得到了全平台支持。尽管许多操作系统在标准文本输出中越来越多地支持ANSI，但大多数情况下ANSI支持是由终端模拟器完成的（例如Unix/Linux上的xterm、GNOME终端、Konsole，MacOS上的OS X Terminal或ZTerm，以及IBM PC上的许多通信程序）。

Unix和AmigaOS都在操作系统中包含了对ANSI的一些支持，因此在这些平台上运行的程序广泛使用ANSI。类Unix操作系统可以通过像termcap和curses函式库之类的库来生成ANSI代码，许多软件使用这些库升级显示方式。这些库也应该支持非ANSI终端，但是现在很少有人测试，所以很可能已经不起作用了。许多游戏和shell脚本直接输出ANSI序列（如彩色的提示信息），因此无法在不支持ANSI的终端上运行。

AmigaOS不仅支持输出到屏幕上的文本使用ANSI序列，还支持打印机驱动程序使用ANSI序列（需要AmigaOS的专有扩展，这会将它们转换为与特定打印机实际通信所需的代码）。

尽管ANSI很普及，却并没有得到全平台支持。比如原始的“经典”Mac OS就没有内置对ANSI的支持，再比如Atari ST使用的是VT52改编的命令系统，需要用一些扩展程序来支持颜色显示。

### Windows和DOS

MS-DOS 1.x不支持ANSI或任何其他转义序列，只有少数控制字符（BEL、CR、LF、BS）可以由底层BIOS解释，所以几乎不可能做出任何全屏应用程序。所有显示效果都必须通过BIOS调用，或者直接控制IBM PC硬件来完成，调用速度非常慢。

DOS 2.0引入了添加设备驱动程序来支持ANSI转义序列的功能（事实上的标准是ANSI.SYS，但也使用了ANSI.COM、NANSI.SYS和ANSIPLUS.EXE等其他程序。因为绕过了BIOS，所以这些程序的速度比以前快了不少）。但由于实际运行速度仍然比较慢，以及默认并没有安装，所以还是很少得到利用。应用程序往往还是继续用直接控制硬件的方式来显示所需的文本。ANSI.SYS和类似的驱动程序继续在Windows 9x上工作，直到Windows Me，在NT衍生系统中用于在NTVDM下执行的16位传统程序。

Win32控制台完全不支持ANSI转义序列。不过有一些控制台的替代品或者附加软件具有解释程序输出的ANSI转义序列的功能，例如JP Software的TCC（以前的4NT）、Michael J. Mefford的ANSI.COM、Jason Hood的ANSICON和Maximus5的ConEmu。有一个Python软件包在内部解释了打印文本中的ANSI转义序列，将它们转换为系统调用来操纵颜色和光标位置，以便更容易地将使用ANSI的Python代码移植到Windows。

2016年，在Windows 10发布“Threshold 2”时，微软开始在控制台应用程序中支持ANSI转义序列，使得从Unix移植软件或者远程访问Unix变得更容易。这是与Windows Subsystem for Linux一起完成的，允许基于终端的类Unix软件在Win32控制台中使用转义序列。2019年，微软推出了Windows Terminal，并且正在用其替换掉Win32控制台

## 转义序列

序列具有不同的长度。所有序列都以ASCII字符`'''ESC'''`（27 / 十六进制 0x1B）开头，第二个字节则是0x40–0x5F（ASCII `@A–Z[\]^_`）范围内的字符。

标准规定，在8位环境中，这两个字节的序列可以合并为0x80-0x9F范围内的单个字节（详情请参阅C1控制字符集）。但是，在现代设备上，这些代码通常用于其他目的，例如UTF-8的一部分或CP-1252字符，因此并不使用这种合并的方式。

除ESC之外的其他C0代码（通常是BEL，BS，CR，LF，FF，TAB，VT，SO和SI）在输出时也可能会产生与某些控制序列相似或相同的效果。

序列｜C1｜名称｜作用

ESC N｜0x8e｜SS2 – Single Shift Two｜从其中一个替代字符集中选择一个字符。在xterm中，SS2选择G2字符集，SS3选择G3字符集。

ESC O｜0x8f｜SS3 – Single Shift Three

ESC P｜0x90｜DCS – 设备控制字符串（Device Control String）｜控制设备。在xterm中，这个序列的使用包括定义用户自定义的密钥，以及请求或设置Termcap/Terminfo数据。

ESC ｜0x9b｜CSI - 控制序列导入器（Control Sequence Introducer）｜大部分有用的序列，请参阅下一节。结束于ASCII 64到126 (`@`到`~`/十六进制0x40到0x7E).

ESC \｜0x9c｜ST – 字符串终止（String Terminator）｜终止其他控件（包括APC，DCS，OSC，PM和SOS）中的字符串。

ESC ｜0x9d｜OSC – 操作系统命令（Operating System Command）｜启动操作系统使用的控制字符串。OSC序列与CSI序列相似，但不限于整数参数。通常，这些控制序列由ST终止。在xterm中，它们也可能被BEL终止。例如，在xterm中，窗口标题可以这样设置：`OSC 0;this is the window title BEL`。

ESC X｜0x98｜SOS – 字符串开始（Start of String）｜引用由ST终止的一串文本的参数。这些字符串控制序列的用途由应用程序或私有规则来定义。这些函数没有实现，参数被xterm忽略。

ESC ^｜0x9e｜PM – 私有消息（Privacy Message）

ESC _｜0x9f｜APC – 应用程序命令（Application Program Command）

ESC c｜RIS – 重置为初始状态（Reset to Initial State）｜将设备重置为原始状态。可能包括（如果适用的话）：重置图形格式，清除制表符，重置为默认字体等等。

按下键盘上的特殊键，以及输出xterm CSI、DCS或OSC序列，常常用于产生从终端发送到计算机的CSI，DCS或OSC序列，就像用户使用键盘输入的一样。

## CSI序列

CSI序列由`ESC [`、若干个（包括0个）“参数字节”、若干个“中间字节”，以及一个“最终字节”组成。各部分的字符范围如下：

组成部分｜字符范围｜ASCII

参数字节｜0x30–0x3F｜`0–9:;<=>?`

中间字节｜0x20–0x2F｜空格、`!"#$%&'()*+,-./`

最终字节｜0x40–0x7E｜@A–Z\^_`a–z

所有常见的序列都只是把参数用作一系列分号分隔的数字，如`1;2;3`。缺少的数字视为0（如`1;;3`相当于中间的数字是0，`ESC[m`这样没有参数的情况相当于参数为0）。某些序列（如CUU）把0视为1，以使缺少参数的情况下有意义。一部分字符定义是“私有”的，以便终端制造商可以插入他们自己的序列而不与标准相冲突。包括参数字节`<=>?`的使用，或者最终字节0x70–0x7F（`p–z 当CSI序列含有超出0x20–0x7E范围的字符时，其行为是未定义的。这些非法字符包括C0控制字符（范围0–0x1F）、DEL（0x7F），以及高位字节。

```
   `ESC[ … 38;5;<n> … m`选择前景色（n是下表中的一种）
   `ESC[ … 48;5;<n> … m`选择背景色
     0-  7：标准颜色（同`ESC &#91; 30–37 m`）
     8- 15：高强度颜色（同`ESC &#91; 90–97 m`）
    16-231：6 × 6 × 6 立方（216色）: 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
   232-255：从黑到白的24阶灰度色
```

```
   `ESC[ … 38:5:<n> … m`选择前景色（n是下表中的一种）
   `ESC[ … 48:5:<n> … m`选择背景色
```

216色

16｜17｜18｜19｜20｜21｜22｜23｜24｜25｜26｜27｜28｜29｜30｜31｜32｜33｜34｜35｜36｜37｜38｜39｜40｜41｜42｜43｜44｜45｜46｜47｜48｜49｜50｜51

52｜53｜54｜55｜56｜57｜58｜59｜60｜61｜62｜63｜64｜65｜66｜67｜68｜69｜70｜71｜72｜73｜74｜75｜76｜77｜78｜79｜80｜81｜82｜83｜84｜85｜86｜87

88｜89｜90｜91｜92｜93｜94｜95｜96｜97｜98｜99｜100｜101｜102｜103｜104｜105｜106｜107｜108｜109｜110｜111｜112｜113｜114｜115｜116｜117｜118｜119｜120｜121｜122｜123

124｜125｜126｜127｜128｜129｜130｜131｜132｜133｜134｜135｜136｜137｜138｜139｜140｜141｜142｜143｜144｜145｜146｜147｜148｜149｜150｜151｜152｜153｜154｜155｜156｜157｜158｜159

160｜161｜162｜163｜164｜165｜166｜167｜168｜169｜170｜171｜172｜173｜174｜175｜176｜177｜178｜179｜180｜181｜182｜183｜184｜185｜186｜187｜188｜189｜190｜191｜192｜193｜194｜195

196｜197｜198｜199｜200｜201｜202｜203｜204｜205｜206｜207｜208｜209｜210｜211｜212｜213｜214｜215｜216｜217｜218｜219｜220｜221｜222｜223｜224｜225｜226｜227｜228｜229｜230｜231

灰度色

232｜233｜234｜235｜236｜237｜238｜239｜240｜241｜242｜243｜244｜245｜246｜247｜248｜249｜250｜251｜252｜253｜254｜255

### 24位

随着16位到24位颜色的“真彩色”显卡的普及，Xterm、KDE的Konsole，以及所有基于libvte的终端（包括GNOME终端）支持了ISO-8613-3的24位前景色和背景色设置。

```
   `ESC[ … 38;2;<r>;<g>;&lt;b> … m`选择RGB前景色
   `ESC[ … 48;2;<r>;<g>;&lt;b> … m`选择RGB背景色
```

作为ISO / IEC国际标准8613-6采用的ITU的T.416信息技术-开放文档体系结构（ODA）和交换格式：字符内容体系结构给出了一个似乎不太受支持的替代版本：

```
   `ESC[ … 38:2:<Color-Space-ID>:<r>:<g>:&lt;b>:<unused>:<CS tolerance>:<Color-Space: 0="CIELUV"; 1="CIELAB">m`选择RGB前景色
   `ESC[ … 48:2:<Color-Space-ID>:<r>:<g>:&lt;b>:<unused>:<CS tolerance>:<Color-Space: 0="CIELUV"; 1="CIELAB">m`选择RGB背景色
```

请注意，这里使用了保留的“:”字符来分隔子选项，这可能是在实际实现中造成混淆的始作俑者。它还使用“3”作为第二个参数来指定使用青-品红-黄方案的方案，“4”用于青-品红-黄-黑的方案，后者使用上面标记为“unused”（“未使用”）的位置作为黑色组件。

还要注意，许多识别“:”作为分隔符的实现错误地忽视了色彩空间标识符参数，并因此改变了其余部分的位置。

## 示例

`CSI 2 J` — 清除屏幕、（在某些设备上）把光标置于1,1位置（左上角）。

`CSI 32 m` — 使文字呈绿色。在MS-DOS上，一般绿色是暗淡的绿色，可以用`CSI 1 m`启用粗体使其变成明亮的绿色，或者将两者合并为`CSI 32 ; 1 m`。MS-DOS ANSI.SYS用粗体状态使字符变亮，闪烁状态（通过`INT 10, AX 1003h, BL 00h`)使背景色变成明亮模式。MS-DOS ANSI.SYS并不直接支持SGR代码90–97和100–107。

`CSI 0 ; 6 8 ; "DIR" ; 13 p` — 重新分配F10键的功能为发送字符串“DIR”和回车符到键盘缓存中，在DOS命令行里会显示当前目录的内容（仅MS-DOS ANSI.SYS）。这种序列有时用于“ANSI炸弹”。这是一个私用编码（如字母p所示），用非标准的扩展使其包含一个字符串参数。如果按标准，会认为字母D是序列的末尾。

`CSI s` — 保存光标的位置。用序列`CSI u`会把光标重置回这个位置。假设当前的光标位置是7（y）、10（x）。序列`CSI s`会保存这两个数值。现在可以把光标移动到其他位置，比如用序列`CSI 20 ; 3 H`或`CSI 20 ; 3 f`把光标移动到20（y）、3（x）。现在如果用序列`CSI u`，光标会回到7（y）、10（x）。某些终端需要使用DEC序列`ESC 7`/`ESC 8`，这得到了更广泛的支持。

### 使用Shell脚本的示例

ANSI转移代码常常用于UNIX和类UNIX终端，以提供语法高亮功能。例如，在兼容的终端上，以下ls命令按类型对文件和目录的名称进行颜色编码。

```
`ls --color`
```

用户可以在脚本中使用转义码，将其作为标准输出或标准错误输出的一部分。例如，下面的GNU sed命令通过反显“WARN”开头的单词的行，以及使用暗红色背景色和亮黄色前景色显示以“ERR”开头的单词（字母大小写被忽略）的行来修饰make命令的输出。突出显示了设置ANSI代码的部分。

```
<span style="white-space:pre-wrap;">make 2&gt;&amp;1 | sed -e 's/.*\bWARN.*/<span style="border:1px solid grey;border-radius:5px;color:white;background:black;font-weight:bolder;">\x1b[7m</span>&<span style="border:1px solid grey;border-radius:5px;">\x1b[0m</span>/i' -e 's/.*\bERR.*/<span style="border:1px solid grey;border-radius:5px;color:yellow;background:maroon;font-weight:bolder;">\x1b[93;41&nbsp;m</span>&<span style="border:1px solid grey;border-radius:5px;">\x1b[0m</span>/i'</span>
```

以下Bash函数会使终端闪烁（通过交替发送反相和正常显示模式代码），直到用户按下任意键。这个函数可以用于当一个冗长的命令终止时提醒用户，用法如`make; flasher`。

```
<span style="white-space:pre-wrap;">flasher () { while true; do printf <span style="border:1px solid grey;border-radius:5px;color:white;background:black;font-weight:bolder;">\\e[?5h</span>; sleep 0.1; printf <span style="border:1px solid grey;border-radius:5px;font-weight:bolder;">\\e[?5l</span>; read -s -n1 -t1 && break; done; }</span>
```

下面这个命令可以重置控制台，类似现代Linux系统的`reset`命令。然而，即使在较早的Linux系统和其他（非Linux）UNIX变体上，也应该能起作用。

```
printf \\033c
```

## 外部链接

- Standard ECMA-48, Control Functions For Coded Character Sets. (5th edition, June 1991), European Computer Manufacturers Association, Geneva 1991 (also published by ISO and IEC as standard ISO/IEC 6429)
- vt100.net DEC Documents
- Xterm / Escape Sequences
- AIXterm / Escape Sequences
- A collection of escape sequences for terminals that are vaguely compliant with ECMA-48 and friends.
- ANSI Escape Sequences
- ITU-T Rec. T.416 (03/93) Information technology – Open Document Architecture (ODA) and interchange format: Character content architectures

## 基本资料

- 日语原文：ANSI X3.64 (ISO/IEC 6429)
- 标准：ECMA-48、ISO/IEC JTC 1 6429、FIPS 86、ANSI X3.64、JIS X 0211
- 分类：ISO/IEC 2022基于控制字符的转义序列
- 其他相关编码：其它控制字符标准：Videotex字符集，JIS X 0207，ISO 6630，DIN 31626，Teletext字符集