人生不能黑白,終端機當然也是

Larry Lu
Starbugs Weekly 星巴哥技術專欄
5 min readAug 15, 2022

--

不知道大家有沒有用過 exa 這個 CLI 工具,他基本上是現代版的 ls(我都直接 alias ls='exa -h')。除了是用 Rust 寫的所以效能很好之外,他還會幫結果上色,讓眼睛看起來更舒服,同事不經意看到你的螢幕時也會覺得你很厲害(X

不過今天的重點不是 exa,而是為什麼 exa 的輸出可以這麼五彩繽紛甚至還能畫線?這就要從 跳脫序列(Escape Sequence) 開始說起了

ANSI Escape Sequence

第一次聽到跳脫序列(Escape Sequence)可能會不知道那是啥,但我們其實很常用到它哦~

像大家都知道在寫程式的時候 \n 代表的是換行、而 \t 是 Tab。這類型 \ 開頭的字元就被稱做跳脫字元\n 並不是字面上的 \n 兩個字元,而是有特別的換行功能,所以如果在終端機中下指令 echo -e "Hello\nWorld" 會看到 HelloWorld 是各自一行

但除了 \n\t 之外其實還有各種奇怪的跳脫字元,而且也不一定都短短的,像顏色也是用跳脫字元來實現的。舉個例子,像 \033[34m 這一串可以把之後的字變成藍色,可以想像成把手上的筆換成藍色的,而 \033[0m 則是把顏色重置

所以 \033[34mHello\033[0mWorld 這一大串就是先拿藍色的筆寫 Hello換回原本的筆後再寫 World,因此只有前面的 Hello 變成藍色,很神奇吧!

CSI Sequence

\033[34m\033[0m 這種格式被稱作 CSI 序列,他們的共通點是都是以 \033[ 開頭、以 m 結尾,中間再填上 SGR 參數,用來設定你想把輸出變成什麼顏色。

那每個數字到底代表什麼顏色呢?我們一起來看看維基上的顏色表,可以看到 34 對應到的是 前景色代碼的藍色,因此 \033[ 34 m 就是把字體顏色設為藍色。

那如果你想要的是 黃底藍字 呢?那就用分號 ; 把黃色背景(43)跟藍字(34)串起來作為 SGR 參數就可以了。實際用 \033[34;43mHelloWorld 馬上就可以看到黃底藍字的 Hello World 哦~

除了顏色之外,SGR 參數還可以用來調整很多東西哦,像是 1 是粗體、3 是斜體、9 是刪除線等等

所以你也可以把他們組起來做出 又斜又粗黃底藍字加刪除線 的 Hello World

因為像這種跳脫字元是通用的,所以不管你寫的是什麼語言都可以用這種方式來上色,像我把上面那串貼到 Node.js 裡面去跑,就會出現漂亮(?)的 Hello World

蛤可是這樣寫起來好醜

雖然說可以這樣幫輸出結果加上顏色,可是程式碼會看起來很醜,不仔細看根本不知道在寫什麼。所以其實各語言都有一些包裝好的 library 可以用,像 JS 就是用 chalk,輕輕鬆鬆就可以上色

如果仔細去看 chalk 的原始碼,會發現他就是把上面那串 \033[ <SGR> m 包裝成一個個 function 讓你方便用而已,所以最後的效果都是一樣的

如果不是寫 JS 的話,像 Go、Rust、Python 也有 coloransi_termyachalk 可以用。下面是 Rust 的 ansi_term 提供的寫法,也是輕輕鬆鬆~

Rust ansi_term 的實作 也是差不多的方式,就是幫你把這堆醜東西封裝起來,眼不見為淨XD

總結

關於可以用 Escape Sequence 來上色這件事,之前參加鐵人賽的時候就簡單寫過~但那時每天都要寫文章沒時間研究得更深入。這次除了教大家怎麼用 SGR 參數之外,還稍微看了 JS 跟 Rust 的 color library 實作,雖然內容不難,但我自己覺得滿有趣的

雖然今天只跟大家介紹 30 到 37 共八種顏色可以用,但隨著現在越來越多終端機支援 256 色,有興趣的話也可以到 wiki 上面看怎麼使用更多其他的顏色,就可以讓終端機的顏色更豐富哦~

--

--

Larry Lu
Starbugs Weekly 星巴哥技術專欄

我是 Larry 盧承億,傳說中的 0.1 倍工程師。我熱愛技術、喜歡與人分享,專長是 JS 跟 Go,平常會寫寫技術文章還有參加各種技術活動,歡迎大家來找我聊聊~