关于ANSI转义序列解读
作者:ScilogyHunter
ANSI转义序列
概念
先看ANSI_escape_code官网上的一段介绍:
In computing, ANSI escape codes (or escape sequences) are a method using in-band signaling
to control theformatting, color, and other output options on video text terminals.To encode
this formatting information, certain sequences of bytes are embedded into the text,which the
terminal looks for and interprets as commands, not ascharacter codes.
- 在计算机系统中,ANSI转义码(或转义序列)是一种使用带内信号控制视频文本终端的格式、颜色和其他输出选项的方法。
- 为了编码这种格式化信息,特定的字节序列被嵌入到文本中,终端将查找并将其解释为命令,而不是字符代码。
终端,现在也叫命令行,在历史上,确实有一种设备就叫终端。其中最为著名的,可能就是 vt100 系列了。我们现在能看到的 terminal 软件都是终端设备的模拟器。虽说终端设备已经作古,但终端的通信控制协议依然有效。
ANSI转义序列
就是终端上通用的通信控制协议,我们可以在命令行下显示粗体、斜体、下划线字符,也可以显示不同的颜色,甚至还能显示简单的动画。
ANSI序列是在二十世纪七十年代引入的标准,用以取代特定终端供应商的序列,并在二十世纪八十年代早期开始在计算机设备市场上广泛使用。
与早期缺少光标移动功能的系统相比,新生的电子公告板系统(BBS)使用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。
支持平台
随着诸多BBS和线上服务广泛使用ANSI,到20世纪80年代中期,ANSI几乎得到了全平台支持。尽管许多操作系统在标准文本输出中越来越多地支持ANSI,但大多数情况下是以终端模拟器的形式(例如Unix上的xterm,或MacOS上的OS X Terminal或ZTerm,以及IBM PC上的许多通信程序)。
Unix和AmigaOS都在操作系统中包含了对ANSI的一些支持,导致在这些平台上运行的程序广泛使用ANSI。 类Unix操作系统可以通过像termcap和curses之类的库来生成ANSI代码,许多软件使用这些库升级显示方式。这些库也应该支持非ANSI终端,但是现在很少有人测试,所以很可能已经不起作用了。许多游戏和shell脚本直接输出ANSI序列(如彩色的提示信息),因此无法在不支持ANSI的终端上运行。
AmigaOS不仅支持输出到屏幕上的文本使用ANSI序列,打印机驱动程序也支持(用AmigaOS的专有扩展),并将它们转换为与特定打印机实际通信所需的代码。
尽管ANSI很普及,却并没有得到全平台支持。比如原始的“经典”Mac OS就没有内置对ANSI的支持,再比如Atari ST使用的是VT52改编的命令系统,用一些扩展程序支持颜色显示。
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变得更容易。
转义序列
序列具有不同的长度。所有序列都以ASCII字符ESC(十进制的27 ,或十六进制 0x1B,或八进制的033,或转义字符\e)开头,第二个字节则是0x40–0x5F(ASCII 的@A–Z[]^_)范围内的字符。
标准规定,在8位环境中,两个字节的序列可以合并为0x80-0x9F范围内的单个字节(详情请参阅C1控制字符集)。但是,在现代设备上,这些代码通常用于其他目的,例如UTF-8的一部分或CP-1252字符,因此并不使用这种合并的方式。
除ESC之外的其他C0代码(通常是BEL,BS,CR,LF,FF,TAB,VT,SO和SI)在输出时也可能会产生与某些控制序列相似或相同的效果。
ANSI转义序列C0列表
ANSI转义序列C1不完整列表
按下键盘上的特殊键,或向终端输出CSI、DCS或OSC请求序列,会产生从终端发送到计算机的CSI,DCS或OSC应答序列,就像用户使用键盘输入的一样。
CSI序列
ANSI转义序列中以 ESC [
开头的叫作 Control Sequence Introducer
,简写为 CSI。
以 CSI 开头的指令有很多,大致可分四类:光标移动指令、清屏指令、字符渲染(Graphic Rendition)指令和终端控制指令。
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{|}~)例如VT320序列 CSI?25h
和 CSI?25l
的作用是打开和关闭光标的显示。
当CSI序列含有超出0x20–0x7E范围的字符时,其行为是未定义的。这些非法字符包括C0控制字符(范围0–0x1F)、DEL(0x7F),以及高位字节。
一些CSI控制序列(不完整列表)
SGR
字符渲指令全称 Select Graphic Rendition,简写为 SGR。
其格式为 CSI n m
,以数字开头,并以 m 结尾,n 的取值范围是 0-107。
又可以分成两类,一类控制字符显示样式,另一类控制显示颜色。
SGR参数列表
颜色设置
3/4位色
初始的规格只有8种颜色,只给了它们的名字。SGR参数30-37选择前景色,40-47选择背景色。相当多的终端将“粗体”(SGR代码1)实现为更明亮的颜色而不是不同的字体,从而提供了8种额外的前景色,但通常情况下并不能用于背景色,虽然有时候反显(SGR代码7)可以允许这样。
例如:
- 在白色背景上显示黑色文字使用ESC[30;47m,
- 显示红色文字用ESC[31m,
- 显示明亮的红色文字用ESC[1;31m。
- 重置为默认颜色用ESC[39;49m,
- 重置所有属性用ESC[0m。
后来的终端新增了功能,可以直接用90-97和100-107指定“明亮”的颜色。当硬件开始使用8位DAC时,多个软件为这些颜色名称分配了24位的代码。下面的图表显示了发送到DAC的一些常用硬件和软件的值。
8位色
随着256色查找表在显卡上越来越常见,相应的转义序列也增加了,以从预定义的256种颜色中选择:
- ESC[ … 38;5;n … m选择前景色
- ESC[ … 48;5;n … m选择背景色
- 0- 7:标准颜色(同ESC [ 30–37 m)
- 8- 15:高强度颜色(同ESC [ 90–97 m)
- 16-231:6 × 6 × 6 立方(216色): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
- 232-255:从黑到白的24阶灰度色
ITU的T.416信息技术-开放文档体系结构(ODA)和交换格式:字符内容体系结构使用“:”作为分隔符:
- ESC[ … 38:5:n … m选择前景色
- ESC[ … 48:5:n … m选择背景色
24位色
随着16位到24位颜色的“真彩色”显卡的普及,Xterm、KDE的Konsole,以及所有基于libvte的终端(包括GNOME终端)支持了ISO-8613-3的24位前景色和背景色设置。
- ESC[ … 38;2;<r>;<g>;<b> … m选择RGB前景色
- ESC[ … 48;2;<r>;<g>;<b> … m选择RGB背景色
作为ISO / IEC国际标准8613-6采用的ITU的T.416信息技术-开放文档体系结构(ODA)和交换格式:字符内容体系结构给出了一个似乎不太受支持的替代版本:
- ESC[ … 38:2:<Color-Space-ID>:<r>:<g>:<b>:<unused>:<CS tolerance>:<Color-Space: 0=“CIELUV”; 1=“CIELAB”>m选择RGB前景色
- ESC[ … 48:2:<Color-Space-ID>:<r>:<g>:<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,这得到了更广泛的支持。
主要网址
xterm:https://invisible-island.net/xterm/
stackoverflow:https://stackoverflow.com/questions/4842424/list-of-ansi-color-escape-sequences
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。