终端及颜色

01 Sep 2024 1517 words 6 minutes BY-SA 4.0
develop cmd

经常使用命令行的童鞋都知道:

命令行软件的输出是可以有颜色的。

ls

终端模拟器显示颜色的原理其实和 C 语言打印含有转义字符的字符串的原理一样,通过 '\x1b' 开头的 ANSI escape code 显示不同的颜色。

color

代码来源

标准

与颜色相关的标准有:

环境变量 TERM

TERM 规定了 ANSI escape code 和颜色的映射关系:

TERM=dumb 哑终端

不支持任何颜色。 除 \x1b 等不可见字符外的可见字符都会被打印。比如 gvim:shell:

gvim

TERM=vt100TERM=linux

支持 8 种基本颜色。 vt100 是 DEC 公司生产的一款终端(键盘和显示器),是最早支持 ANSI escape code 标准的终端之一。

最早的计算机是一台主机连接多台终端供多用户登录。由终端负责将命令行软件的含有 ANSI escape code 的原始输出翻译为有颜色的最终输出。 vt100 只支持 8 种颜色。

TERM=xtermTERM=xterm-256color

支持 256 种颜色。 xterm 是 Unix 最早的终端模拟器之一。

随着时代的进步, Unix 用户可以在电脑上使用图形化用户界面 (那时还只有性能很差的 X Window) 以像素而非字符的形式与程序交互了。 为了能继续使用之前的命令行软件,用户需要先打开一个叫做终端模拟器的程序,在终端模拟器的窗口中继续以字符的形式与之前的命令行软件交互。 这是,由终端模拟器负责将命令行软件的含有 ANSI escape code 的原始输出翻译为有颜色的最终输出。 xterm 只支持 256 种颜色。

TERM=kitty 显示像素

终端模拟器本质上是一个图形化用户界面的软件。不光能显示有颜色的字符,也可以用同样的形式(转义字符)显示像素。 最早在这方面做出尝试的 2 个终端模拟器是 kittyiterm2 。 大概是因为没有事先交流过的缘故它们分别设计了 2 种不同的支持像素的转义字符的协议。另一种标准是 DEC 公司的 sixel 后续的终端模拟器一般都会支持其中至少一种以显示图像(甚至包括 GIF )。

wezterm

尽管显示像素的这些标准出现的时间较迟,已经有一些命令行软件在利用这些标准来实现在终端模拟器浏览 pdf 、浏览网页的功能了。 笔者对此的评价就是上图中楚云飞的台词。

对于不支持以上 3 种协议任意一种的终端模拟器,我们依旧可以用字符去显示图像:

chafa

笔者关于 12 种不同的终端模拟器支持特性的测试。支持显示像素的终端模拟器目前还不多。

TERM 以外

TERM 告诉每一个命令行软件该软件所在的终端模拟器到底支持多少种颜色、是否支持显示像素等等,以好让它们不要使用当前终端模拟器不支持的颜色和功能。 此环境变量由终端模拟器设置用户不应随意更改。

那么用户如何强制该软件是否打印颜色呢?这样的需求是存在的。想象以下把某个命令行软件有颜色的输出保存到一个纯文本文件中。你显然希望 \x1b 这样的字符应该被提前过滤掉。有不少软件使用如下的标准:

--color={always,never,auto}

alwaysnever 很好理解。 auto 作为默认值,只有当输出是标准终端而非重定向到一个文件时才显示颜色。

环境变量

即,一旦用户 export NO_COLOR=1 ,之后的所有尊重此标准的命令行软件都不应显示颜色(输出 ANSI escape code)。

Windows

Windows 的命令行软件使用 Win32 API 来绘制颜色。不过现在的 Windows Terminal 也开始支持 ANSI escape code 了。

https://user-images.githubusercontent.com/32936898/199681341-1c5cfa61-4411-4b67-b268-7cd87c5867bb.png https://user-images.githubusercontent.com/32936898/199681363-1094a0be-85ca-49cf-a410-19b3d7965120.png https://user-images.githubusercontent.com/32936898/199681368-c34c2be7-e0d8-43ea-8c2c-d3e865da6aeb.png