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字符集