Skip to content

给终端文本设置颜色

2025-04-24

在终端打印日志时,突然想到可以带上颜色来凸显信息,我知道这种效果在很多语言中都有三方库快速实现,但是我想研究下原理。

ANSI 转义序列

网上冲浪一番后,了解到命令行颜色的显示原理是基于ANSI转义序列,关于它的介绍,可以看下维基百科的 ANSI转义序列

ANSI转义序列是一套完整的终端控制协议,通过输入特定的字节序列实现对终端输出内容的精确控制。比如可以让你的文本带上样式显示在终端中,但其可控制的远不止文本颜色,还有光标移动、文本擦除、设置字体、屏幕滚动等等,详细的功能可以查看 ANSI/VT100 Terminal Control Escape Sequences

ANSI 也是跨平台兼容的,现阶段各操作系统版本都原生支持了这个标准。它的应用也是非常广泛的,最常见的比如 git status 命令会用颜色区分文件状态,又比如 ls 命令也会彩色化输出,甚至可以利用光标移动和清屏功能来实现终端游戏。总之 ANSI协议的功能很丰富,也是一切终端样式显示的基石。

颜色控制

ANSI 标准内置了一些颜色供我们使用,在上面文档中也列举出来了:

每一个颜色都有一个数值,且区分了前景色背景色。我们用这些数值就可以设置颜色。

ANSI 定义设置颜色的写法为 \033[<参数>m<内容>\033[0m,看到这一串时人可能是懵的,但其实很简单,拆解下:

  • \033[\033代表的是 ASCII 表中的 Esc,它在 ASCII 表中的十进制值是 2733是它的八进制值。ANSI 规定要用 ESC[ 开始,所以写成 \033[
  • <参数>:这个参数就是设置颜色对应的数值,上面截图中那些;
  • m:结束符,表示开始应用样式;
  • <内容>:这个就是你需要设置颜色的文本。
  • \033[0m:表示复位,表示结束应用样式。这个可以不写,不写就表示后面所有内容都应用样式。

WARNING

关于 \033 的写法,在不同的系统或者语言中,可能支持程度不一样,还可以写成 \x1b\u001B等。如果 \033 不行,可以试试其他写法。

综上介绍,我们想要设置一个红色的文本,需要这样写:

bash
"\033[31m这段文本是红色的"

怎么输出到终端呢?以下我用 Mac 电脑,结合 Iterm2 终端演示效果。

可以直接在终端中使用 echo 输出:

在程序开发中,用所使用的语言直接打印也可以。比如用 nodejs可以这样写:

js
// demo.js
// 在我的mac电脑上测试这三种写法都生效

console.log("\033[31m这段文本是红色的")
console.log("\x1b[32m这段文本是绿色的")
console.log("\u001B[33m这段文本是黄色的")

Go 也能生效,后面就用 Go 来演示:

go
// main.go

fmt.Println("\033[31m这段文本是红色的")
fmt.Println("\x1b[32m这段文本是绿色的")
fmt.Println("\u001B[33m这段文本是黄色的")

WARNING

注意⚠️,显示颜色也需要终端支持,如果你的没效果,需要检查所在终端是否兼容ANSI

带上复位序列,则可以结束样式:

go
// 使用 \033[0m 复位,后面的内容恢复默认颜色
fmt.Println("\033[31m这段文本是红色的\033[0m这段文本是默认颜色")

TIP

建议始终在末尾加上复位序列 \033[0m,避免对后续序列的干扰

把数值换成 4 开头的,可以设置背景色,如:

go
// main.go

fmt.Println("\033[41m背景色是红色的\033[0m")
fmt.Println("\x1b[42m背景色是绿色的\033[0m")
fmt.Println("\u001B[43m背景色是黄色的\033[0m")

前景色和背景色可以同时设置:

go
// main.go
fmt.Println("\033[32;41m红色背景绿色字体\033[0m")

// 背景色和前景色顺序调换也可以
// fmt.Println("\033[32;41m红色背景绿色字体\033[0m")

设置RGB颜色

ANSI转义序列还支持 RG B颜色模式,允许精确指定红(R)、绿(G)、蓝(B)三原色的强度(0-255),这样就可以设置超多丰富的颜色了,不仅仅是上面列举的那些。

设置 RGB 模式颜色的语法是:

bash
\033[38;2;R;G;Bm  # 前景色
\033[48;2;R;G;Bm  # 背景色

38 代表设置前景色,48 代表设置背景色,而2 表示开启 RGB 模式,都是固定写法。RGB 分别代表红、绿、蓝的强度,取值范围是 0-255。

以下是几个例子:

go
// main.go

fmt.Println("\033[38;2;255;0;0m红色字体\033[0m")
fmt.Println("\033[38;2;0;255;0m绿色字体\033[0m")
fmt.Println("\033[38;2;0;0;255m蓝色字体\033[0m")

fmt.Println("\033[48;2;255;0;0m红色背景\033[0m")
fmt.Println("\033[48;2;0;255;0m绿色背景\033[0m")
fmt.Println("\033[48;2;0;0;255m蓝色背景\033[0m")

fmt.Println("\033[38;2;148;204;174m随便设置一个颜色\033[0m")

样式修饰符

对于文本样式的修饰,其实不止有颜色,还有以下几个:

text
0	Reset all attributes  // 重置所有文本样式和颜色,恢复终端默认状态
1	Bright                // 提高文本亮度或加粗显示
2	Dim                   // 降低文本亮度
4	Underscore	          // 为文本添加下划线
5	Blink                 // 使文本闪烁(支持度较低,通常分为快速和慢速两种模式)慢速闪烁:\033[5m 快速闪烁:\033[6m
7	Reverse               // 反转前景色和背景色
8	Hidden                // 隐藏文本

各终端对于这些修饰符的兼容性不一,不一定能生效。

首先 0 是重置样式,前面讲过了,就是 \033[0m 序列,可以重置后面的文本样式,这里不再演示了,其他的几种,我直接用 echo 命令演示了:

bash
echo -e "\033[31m正常红色文字\033[0m"
echo -e "\033[1;31m加粗红色文字\033[0m"
echo -e "\033[2;31m降低亮度的红色文字\033[0m"
echo -e "\033[4m带下划线的文字\033[0m"
echo -e "\033[5m闪烁文字\033[0m" # 闪烁 不生效
echo -e "\033[31;47m红字白底\033[7m 颜色反转\033[0m"
echo -e "\033[8m被隐藏的文本\033[0m"

在我的电脑终端中测试效果如上,只有 5 Blink 不生效。

结尾

正如文章开始说的,ANSI 转义序列不仅可以设置文本样式,还有其他玩法,有兴趣的可以多了解下。实际开发中,一般都会用现成的库,比如 nodejs 的 chalk,是一个周下载量破亿的终端颜色打印库。而本文,只是兴趣使然,简单了解下原理。