热门问题
时间线
聊天
视角
ANSI轉義序列
来自维基百科,自由的百科全书
Remove ads
ANSI轉義序列(ANSI escape sequences)是一種帶內信號的轉義序列標準,用於控制視頻文本終端上的光標位置、顏色和其他選項。在文本中嵌入確定的字節序列,大部分以ESC
轉義字符和"["字符開始,終端會把這些字節序列解釋為相應的指令,而不是普通的字符編碼。
ANSI序列是在二十世紀七十年代引入的標準,用以取代特定於終端供應商的序列,並在二十世紀八十年代早期開始在計算機設備市場上廣泛使用。與早期缺少光標移動功能的系統相比,新生的電子公告板系統使用ANSI序列改進其顯示。正是因為這個原因,ANSI序列變成了所有製造商共同採用的標準。
在21世紀,儘管硬件文本終端已經越來越少了,但ANSI標準依然存在,因為大多數終端模擬器會對部分ANSI轉義序列進行解釋。一個值得注意的例外是,在微軟Windows 10更新TH2之前,Windows操作系統的Win32控制台是不支持ANSI轉義序列的。
Remove ads
歷史
最初,幾乎每個視頻終端製造商都各自添加了特定的轉義序列用於執行一些特殊操作,比如把光標置於屏幕上的某個位置。舉例來說,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的國際標準[1]。1994年,ANSI取消了其標準,以支持國際標準。
第一個支持這個標準的流行視頻終端是1978年推出的Digital VT100[2]。這個終端在市場上非常成功,引發了各種各樣的仿製品,其中最早和最流行的是1979年的Zenith Z-19[3]。其他品牌還有Qume QVT-108,Televideo TVI-970,Wyse WY-99GT。另外,許多其他品牌的終端也不同程度地兼容可選的「VT100」、「VT103」或「ANSI」模式。 隨着越來越多的軟件(尤其是BBS系統)普及,越來越多的軟件依賴轉義序列起作用,導致幾乎所有新的終端和終端模擬器都支持了此標準。
1981年,ANSI X3.64被美國政府採用(FIPS 86)。後來,美國政府停止複製行業標準,所以FIPS 86又被撤回了[4]。
ECMA-48已經經歷了多次更新換代,目前是從1991年開始的第5版。它也被ISO和IEC用作標準ISO/IEC 6429。
Remove ads
平台支持

隨着諸多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的專有擴展,這會將它們轉換為與特定打印機實際通信所需的代碼[5])。
儘管ANSI很普及,卻並沒有得到全平台支持。比如原始的「經典」Mac OS就沒有內置對ANSI的支持,再比如Atari ST使用的是VT52改編的命令系統,需要用一些擴展程序來支持顏色顯示[6]。
MS-DOS 1.x不支持ANSI或任何其他轉義序列,只有少數控制字符(BEL、CR、LF、BS)可以由底層BIOS解釋,所以幾乎[nb 1]不可能做出任何全屏應用程序。所有顯示效果都必須通過BIOS調用,或者直接控制IBM PC硬件來完成,調用速度非常慢。
DOS 2.0引入了添加設備驅動程序來支持ANSI轉義序列的功能(事實上的標準是ANSI.SYS,但也使用了ANSI.COM[7]、NANSI.SYS[8]和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[9]和Maximus5的ConEmu。有一個Python軟件包[10]在內部解釋了打印文本中的ANSI轉義序列,將它們轉換為系統調用來操縱顏色和光標位置,以便更容易地將使用ANSI的Python代碼移植到Windows。
2016年,在Windows 10發布「Threshold 2」[11]時,微軟開始在控制台應用程序中支持ANSI轉義序列,使得從Unix移植軟件或者遠程訪問Unix變得更容易。這是與Windows Subsystem for Linux一起完成的,允許基於終端的類Unix軟件在Win32控制台中使用轉義序列。2019年,微軟推出了Windows Terminal,並且正在用其替換掉Win32控制台[12]
Remove ads
轉義序列
序列具有不同的長度。所有序列都以ASCII字符ESC
(27 / 十六進制 0x1B)開頭,第二個字節則是0x40–0x5F(ASCII @A–Z[\]^_
)範圍內的字符。[13]:5.3.a
標準規定,在8位環境中,這兩個字節的序列可以合併為0x80-0x9F範圍內的單個字節(詳情請參閱C1控制字符集)。但是,在現代設備上,這些代碼通常用於其他目的,例如UTF-8的一部分或CP-1252字符,因此並不使用這種合併的方式。
除ESC之外的其他C0代碼(通常是BEL,BS,CR,LF,FF,TAB,VT,SO和SI)在輸出時也可能會產生與某些控制序列相似或相同的效果。
按下鍵盤上的特殊鍵,以及輸出xterm CSI、DCS或OSC序列,常常用於產生從終端發送到計算機的CSI,DCS或OSC序列,就像用戶使用鍵盤輸入的一樣。
Remove ads
CSI序列
CSI序列由ESC [
、若干個(包括0個)「參數字節」、若干個「中間字節」,以及一個「最終字節」組成。各部分的字符範圍如下:
所有常見的序列都只是把參數用作一系列分號分隔的數字,如1;2;3
。缺少的數字視為0(如1;;3
相當於中間的數字是0,ESC[m
這樣沒有參數的情況相當於參數為0)。某些序列(如CUU)把0視為1,以使缺少參數的情況下有意義:F.4.2。
一部分字符定義是「私有」的,以便終端製造商可以插入他們自己的序列而不與標準相衝突。包括參數字節<=>?
的使用,或者最終字節0x70–0x7F(p–z{|}~
)例如VT320序列CSI?25h
和CSI?25l
的作用是打開和關閉光標的顯示。
當CSI序列含有超出0x20–0x7E範圍的字符時,其行為是未定義的。這些非法字符包括C0控制字符(範圍0–0x1F)、DEL(0x7F),以及高位字節。
Remove ads
選擇圖形再現(SGR)參數
Remove ads
顏色
初始的規格只有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的一些常用硬件和軟件的值。[來源請求]
隨着256色查找表在顯卡上越來越常見,相應的轉義序列也增加了,以從預定義的256種顏色中選擇:[17]
ESC[ … 38;5;<n> … m
选择前景色(n是下表中的一种)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)和交換格式:字符內容體系結構[18]使用「:」作為分隔符:
ESC[ … 38:5:<n> … m
选择前景色(n是下表中的一种)ESC[ … 48:5:<n> … m
选择背景色
Remove ads
隨着16位到24位顏色的「真彩色」顯卡的普及,Xterm[14]、KDE的Konsole[19],以及所有基於libvte的終端[20](包括GNOME終端)支持了ISO-8613-3的24位前景色和背景色設置。[17]
ESC[ … 38;2;<r>;<g>;<b> … m
选择RGB前景色ESC[ … 48;2;<r>;<g>;<b> … m
选择RGB背景色
作為ISO / IEC國際標準8613-6採用的ITU的T.416信息技術-開放文檔體系結構(ODA)和交換格式:字符內容體系結構[18]給出了一個似乎不太受支持的替代版本:
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」(「未使用」)的位置作為黑色組件。
還要注意,許多識別「:」作為分隔符的實現錯誤地忽視了色彩空間標識符參數,並因此改變了其餘部分的位置。
Remove ads
示例
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
,這得到了更廣泛的支持。
ANSI轉移代碼常常用於UNIX和類UNIX終端,以提供語法高亮功能。例如,在兼容的終端上,以下ls命令按類型對文件和目錄的名稱進行顏色編碼。
ls --color
用戶可以在腳本中使用轉義碼,將其作為標準輸出或標準錯誤輸出的一部分。例如,下面的GNU sed命令通過反顯「WARN」開頭的單詞的行,以及使用暗紅色背景色和亮黃色前景色顯示以「ERR」開頭的單詞(字母大小寫被忽略)的行來修飾make命令的輸出。突出顯示了設置ANSI代碼的部分。[21]
make 2>&1 | sed -e 's/.*\bWARN.*/\x1b[7m&\x1b[0m/i' -e 's/.*\bERR.*/\x1b[93;41 m&\x1b[0m/i'
以下Bash函數會使終端閃爍(通過交替發送反相和正常顯示模式代碼),直到用戶按下任意鍵[22]。這個函數可以用於當一個冗長的命令終止時提醒用戶,用法如make; flasher
[23]。
flasher () { while true; do printf \\e[?5h; sleep 0.1; printf \\e[?5l; read -s -n1 -t1 && break; done; }
下面這個命令可以重置控制台,類似現代Linux系統的reset
命令。然而,即使在較早的Linux系統和其他(非Linux)UNIX變體上,也應該能起作用。
printf \\033c
參見
腳註
參考資料
外部連結
Wikiwand - on
Seamless Wikipedia browsing. On steroids.
Remove ads