终端

01 Sep 2024 2186 words 8 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 系统预置的 conhost 一直使用另一套自创的标准,通过一些 Win32 API 改变颜色。你可以理解为:打印一段字符,调用 API 修改颜色,再打印一段字符,再调用 API 修改颜色……而非原先的打印一段包含转义字符的字符串。这确确实实增加了开发者兼容的负担,甚至在有些情况下根本无法实现。站在用户的角度,直观的感受就是命令行软件数量的减少和即便支持也会有用户体验的下降。这种情况有可能改变吗?如果有人试图在 Windows 平台开发一个支持 ANSI escape code 的终端模拟器,他面临的情况是:所有已有的 Windows 命令行软件都使用 Win32 API 反而不能支持他的终端模拟器。如果又有命令行软件开发者开发支持 ANSI escape code 的 Windows 命令行软件,那么这个软件无法保证用户一定会使用支持 ANSI escape code 的终端模拟器,一旦遇到用户打开 Windows command shell 运行这个软件,就会看到 TERM=dumb 时看到的乱码。为了防止这种情况,命令行软件开发者均不可能使用 ANSI escape code 。

直到 Windows 10 1511 对 ANSI escape code 的支持,离 ANSI escape code 标准问世都已经过了 38 年了。三国从最后一个称帝的国家到第一个灭亡的国家也不过 37 年。这个功能真的困难到需要 Windows 开发者需要这么长时间才能支持吗?

诚然,如今 Windows 平台命令行软件生态环境恶劣的原因不止其一。但笔者认为其最大的原因在于态度:

弱小和无知不是生存的障碍,傲慢才是。

– 刘慈欣《三体:死神永生》

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