Windows命令行中正确显示颜色

温馨提示:点击页面下方以展开或折叠目录

摘要:win10的cmd对颜色的显示不太友好,在捯饬的过程中差点把电脑搞崩。

文章说明
文章作者:鴻塵
参考资料:

文章链接:Windows命令行中正确显示颜色

1.背景

为了搞好这个问题,差点把电脑给搞崩了,在这里特意记录下来,算是留给自己的一个教训。

临近毕业,这两天什么事情都没有,就等着参加毕业典礼然后跑路。就想着写点东西吧,hexo部署的时候无法正常显示颜色。如图(注意最后一行):
颜色显示异常
颜色显示正常

其实呢,这个问题早就出现了,见Hexo博客搭建(1)——建站及部署之部署Hexo,只不过一直没管它,现在闲下来了就想拯救一下处女座强迫症。

不仅如此,cmd中只能识别^[[35m 文字 ^[[0m而不能识别\33[35m 文字 \33[0m,也就是说无法正确转义\033

需要注意的是,^[是一个字符,且只能在命令行下通过组合键Ctrl + [输入(还有其他方式输入,见后文)。

鉴于以上问题,在经过较长时间的折腾后,找到了一个可用的方法:ANSICON

2.解决方案

2.1.colorama

在Python中显示颜色主要参考「解决CMD命令行窗口不显示颜色问题python」,用到的库为colorama,代码如下:

1
2
3
4
from colorama import init 
init(autoreset=True)

print("\033[35m 紫色 \033[0m") #紫色

上述方法通过颜色代码实现颜色的显示,也可以使用Fore设置颜色:

1
2
3
4
5
6
from colorama import init, Fore
init(autoreset=True)

print(Fore.YELLOW + "黄色")
print("普通文字")
print(Fore.MAGENTA + "洋红色")

colorama方法只适用于python程序在终端上打印彩色文字,并不能解决其他程序的输出。

2.2.ANSICON

鉴于上述问题,在查找了海量资料后,参考「cmd命令提示符文本颜色输出」,最终找到了ANSICON
ANSICON基本上可以完美解决遇到的关于cmd颜色的所有问题,这是它的自我介绍:

ANSICON provides ANSI escape sequences for Windows console programs. It provides much the same functionality as ANSI.SYS does for MS-DOS.

在64位Windows上,ANSICON包含了主程序ansicon.exe和扩展ANSI64.dll,在cmd中运行该程序即可开启一个子shell,在子shell中即可正常显示颜色,不会出现图一的问题。

ANSICON帮助信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
ANSICON by Jason Hood <jadoxa@yahoo.com.au>.
Version 1.89 (29 April, 2019). Freeware.
http://ansicon.adoxa.vze.com/

Process ANSI escape sequences in Windows console programs.

ansicon [-lLEVEL] [-i] [-I] [-u] [-U] [-m[ATTR]] [-p[u]]
[-e|E STRING | -t|T [FILE...] | PROGRAM [ARGS]]

-l set the logging level (1=process, 2=module, 3=function,
+4=output, +8=append, +16=imports, +32=files) for PROGRAM
-i install - add ANSICON to CMD's AutoRun entry (also implies -p)
-u uninstall - remove ANSICON from the AutoRun entry
-I -U use local machine instead of current user
-m use grey on black ("monochrome") or ATTR as default color
-p hook into the parent process
-pu unhook from the parent process
-e echo STRING
-E echo STRING, don't append newline
-t display files ("-" for stdin), combined as a single stream
-T display files, name first, blank line before and after
PROGRAM run the specified program
nothing run a new command processor, or display stdin if redirected

ATTR is one or two hexadecimal digits; please use "COLOR /?" for details.
It may start with '-' to reverse foreground and background (but not for -p).

由上可知,直接运行该程序将不带任何参数,开启一个新的命令行进程,这也是后来悲催的直接原因。现在看来,貌似只需要加上-i选项将其添加到cmd的AutoRun即可。

3.采坑之路

3.1.问题产生

到目前为止,好像一切正常,文章开始说的「差点把电脑搞崩」又是怎么回事呢?

因为担心会出现其他问题,所以并没有安装ANSICON,开启子shell好像也没有什么问题,无非就是每次都要手动输入命令/path/to/ansicon.exe。这也不是什么问题,只要把ansicon.exe文件路径加入到环境变量中即可。
为了省事我直接把ansicon.exeANSI64.dll复制到C:/Windows/System32/目录下,这样一来在任何命令行下都可以直接运行ansicon命令了。

当需要正常显示颜色时,输入ansicon即可,如图所示:
ansicon命令开启子shell
上图中,直接打印颜色将显示乱码,在ansicon的子shell中则可以正常显示,输入exit才可退出shell。此时再打印颜色仍会乱码,因为只有在ansicon的shell中才可以正常显示。

在查资料的时候,偶然看到了一篇文章:CMD窗口无法显示带颜色文字输出。文章中提到,利用注册表的AutoRun字符串值可以实现在打开CMD窗口时自动执行命令。于是,我就设想修改注册表,在每次打开CMD的时候让他自动执行ansicon命令,那么就不需要手动输入了。

说干就干,Win + R打开运行,输入regedit打开注册表编辑器,定位到计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor下,新建字符串值AutoRun,双击该值,在数值数据中填写ansicon,一气呵成。
修改注册表

此时我已经迫不及待地要测试了,然而,当我打开cmd的时候,窗口中却疯狂打印Microsoft Windows [版本 10.0.18363.1556](c) 2019 Microsoft Corporation。保留所有权利。,此时我已经感觉不妙。好在它只开了一个窗口(注意,这是一个伏笔……),我不得不一直按Ctrl + C让它停下来,甚至直接叉掉这个窗口。

我又查了半天,一直都以为是注册表修改方式不对,又不知道在哪里看到了cmd /k xxx这样的一个命令,就是这个命令让我的电脑直接崩溃。该命令会打开一个新窗口来执行xxx命令。于是抱着试一试的心态我把上面注册表的数值数据改成了cmd /k ansicon,当我打开CMD窗口的一瞬间,电脑内存急剧增加,无限开启新窗口并执行ansicon命令。

自此走上了修电脑的艰难之路。

3.2.艰难解决

由于电脑内存卡爆,无法进行任何操作,就算想删除注册表值也没办法,因为鼠标键盘根本动不了。无奈之下,准备重启电脑,跟它抢速度,在内存爆满之前把注册表改回来。事实证明我还是太天真了,电脑一开机他就开始了,根本不给时间你去做其他操作,如图:
内存爆满

到这里已经没有任何办法了,系统还原也不行,因为我很早就删除了系统还原点(只为节省那么一丢丢内存…),现在只能重装系统了,甚至连U盘启动盘都做好了。重装系统倒是无所谓,但是电脑里有很多重要的文件、配置、安装的软件等。我真的不想重装系统,但是没办法啊!

上图是准备重装系统之前拍的照,为的是留一个桌面布局,可以看到右侧命令行窗口边缘厚厚的一层黑边,都不知道开了多少个窗口了。

从U盘重装系统还要设置一下BIOS,开启UEFI什么的。然而哪有那么顺利,就在我失败了无数次一心想要操作系统的时候,他却提示各种错误,要么是某个地方设置不对、要么是某个选项没有开启。在反复的重启和设置中,突然发现了一个修复的选项。在这种连系统都不让我重装的情况下,无疑给了我一丝希望。

然而,新的问题又出现了,所有的修复选项都试过了还是没用,这让我整个人都不好了,一度濒临崩溃。

世事总是这样,在你最绝望的时候才会显现一丝曙光。

在某一个修复选项中,可以打开命令行窗口,目测盘符X应该是U盘吧,Source目录就是启动盘的位置。如图所示:
命令行窗口X

但是一个命令行能干什么呢?这里的命令行是有管理员权限的,最直接的想法就是在这里删除注册表值,然后重启就完美了。
搜了一下,发现还真有操作注册表的命令REG,还有对应的QUREYADDDELETE等选项,此处参考了特殊命令之REG命令。这令我大喜过望,感觉胜利就在眼前。然而,当我查询HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor下的值时,却没有AutoRun这一项(如上图),只有如下几项:

1
2
3
4
CompletionChar      REG_DWORD    0x9
DefaultColor REG_DWORD 0x0
EnableExtensions REG_DWORD 0x1
PathCompletionChar REG_DWORD 0x9

通过对比3.1节《问题产生》的图二和上图,唯独少了AutoRun这一项。这另外百思不得其解的同时,也是十分郁闷。我测试过REG ADDREG DELETE,好像都成功了,为何这里就查询不到呢?看来这个方法又行不通了。

就在我一筹莫展的时候,突然灵机一动,产生问题的根本原因在于无限启动新窗口从而运行ansicon命令,那我可以人为破坏掉他的运行环境啊。
于是我在命令行里试着删除文件C:\Windows\System32\ANSI64.dll,结果成功了。

赶紧重启电脑,尽管仍然会无限开启新窗口,但果然没那么卡了,因为ansicon命令无法正常运行。于是可以打开注册表编辑器,删除掉罪魁祸首AutoRun,再重启电脑就恢复正常了。

至此,历经千辛万苦,电脑总算是修好了,可算是不需要重装系统了。

4.附录

4.1.ANSI颜色序列格式

本段来自转义序列Escape Sequences及Linux echo命令多种颜色显示
在计算机界,ANSI转义编码(escape code)或者转义序列(escape sequences)是带内信号(元数据和控制信号,译者注)控制视频文字终端的格式、颜色、其他输出选项的一种方法。
为了编码这些格式信息,它把某种字节序列嵌入到文本中,该序列必须特别的解释,且不应该作为字符的本义。
尽管硬件字符终端在21世纪已经变得很愈来愈少见,这种标准依然具有实用价值,是因为大多数终端仿真器至少还能解释在输出文本中的一些ANSI转义序列。
但微软的win32控制台组件就是一个明显的例外。

上文中的「\033[35m」和「\033[0m」就是ANSI转义序列(ANSI escape code/sequence),转义序列使用ESC控制字符开始,ESC键位于键盘左上角,其对应的ASCII码为\033(八进制)\27(十进制)\0x1b(十六进制)

通用的控制文本颜色的转义序列格式为CSI n1[;n2[;...]] m,其中CSI全称为「控制序列引导器(Control Sequence Introducer/Initiator)」,即上述\033\x1b\e等;n1n2等表示SGR参数,多个SGR参数可以组合使用,见下表。

通常,我们只需要用到表中部分属性,更详细的属性值可参考命令行里输出带颜色的字体

一般格式:CSI[显示方式;前景色;背景色m 文字 CSI[0m

注:经测试,在Linux下\033\x1b\e可用,\33\0x1b\27不可用。
注:在Windows下只有\033\33\x1b^[可用(不一定准确),\e不可用。

编码 说明 备注
0 关闭所有格式,还原为初始状态 终端默认设置
1 粗体/高亮显示
2 模糊/弱化 不是所有的终端仿真器都支持,只有少数仿真器支持
3 斜体 不是所有的终端仿真器都支持,只有少数仿真器支持
4 下划线(单线)
5 闪烁(慢)
6 闪烁(快) 不是所有的终端仿真器都支持,只有少数仿真器支持
7 交换背景色与前景色(反显)
8 隐藏(伸手不见五指,啥也看不见) 不是所有的终端仿真器都支持,只有少数仿真器支持
22 设置一般密度
24 关闭下划线
25 关闭闪烁
27 关闭反向图像,即关闭7
30-37 前景色,即30+xx表示不同的颜色(参见下面的「颜色表」)
38 在缺省的前景颜色上设置下划线
39 在缺省的前景颜色上关闭下划线
40-47 背景色,即40+xx表示不同的颜色(参见下面的「颜色表」)
49 设置缺省黑色背景
颜色值x 前景色编码 背景色编码 颜色 效果
0 30 40 黑色 黑色
1 31 41 红色 红色
2 32 42 绿色 绿色
3 33 43 黄色 黄色
4 34 44 蓝色 蓝色
5 35 45 紫色 紫色
6 36 46 青色 青色
7 37 47 白色 白色

4.2.设置颜色

一般格式:CSI [ 显示方式; 前景色; 背景色 m 文字部分 CSI [ 0 m

CSI 显示方式 前景色 背景色
\033 \x1b \e
ESC(^[)
0-9 30-37 40-47

需要说明的是,在同一处的CSI最好保持一致,「显示方式」、「前景色」和「背景色」的顺序不重要。

关于Windows下CMD中ESC(^[)的输入方式,参考《Windows cmd(DOS)命令窗口中echo命令ANSI转义显示彩色字或背景》

Windows下CMD中^[是ANSI的ESC一个字符(注意^[是一个字符,就好比我们Ctrl + C时显示的^C一样),并不是我们看到的键盘上左上角那个ESC按键。其ASCII码值的十进制是27, 八进制是33(一般写为\033),十六进制是1b(一般写为\x1b)。其输入方法有以下几种:

  • 方法一(只能在CMD窗口中输入):在CMD窗口中按Ctrl + [组合键即可,这种方法最简单。
  • 方法二(只能在CMD窗口中输入):在CMD窗口中按Alt + 2 + 7组合键即可,注意必须是小键盘上的数字键27,先按住Alt不放再按27最后放开Alt。如果没有数字小键盘,则不能用这种方式。
  • 方法三(编辑器中先输入再替换):略。垃圾软件不配。