cmd 无法显示带颜色字体

2021-07-21 16:38:12 +08:00
 Kasumi20

一个 Rust 编写的程序,Cargo 运行正常,单独启动就乱码,不知道为什么

PowerShell 正常

2340 次点击
所在节点    Windows
12 条回复
ipwx
2021-07-21 16:44:36 +08:00
可能 cargo 有魔法。
----

不是抖段子。[31m 这种是 unix 终端上用来切换终端文字颜色的特殊字符,但是在 windows 上正确的做法是调用 windows api 。cmd.exe 看上去并不理会这种特殊字符。而 powershell 可能照顾了这些。cargo 可能自己解析了这部分输出并正确调用了 windows api 。
ipwx
2021-07-21 16:45:50 +08:00
Kasumi20
2021-07-21 16:53:49 +08:00
@ipwx

谢谢回复,用的是 https://github.com/mackwic/colored 这个库,有 winapi 的依赖,看了一下好像确实没怎么调用 WinAPI
ysc3839
2021-07-21 17:52:59 +08:00
@ipwx Windows 10 的 conhost 是已经支持 escape sequence 更改颜色的,不过要程序主动开启。
但是 cmd 是会开启的,所以不应该出现 cmd 有问题但是 PowerShell 没问题的情况。
用 cargo 没问题说明 cargo 开启了这个功能。
yolee599
2021-07-21 18:19:15 +08:00
int main(int argc, char *argv[])
{
HANDLE hdl = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hdl, FOREGROUND_RED | FOREGROUND_INTENSITY);
printf("Hello ");
SetConsoleTextAttribute(hdl, FOREGROUND_GREEN | FOREGROUND_INTENSITY);
printf("world!\n");
SetConsoleTextAttribute(hdl, FOREGROUND_INTENSITY);
return 0;
}
yolee599
2021-07-21 18:29:08 +08:00
Linux 主要输出到终端,做成一个标准了,无论是 xshell 还是 SecureCRT 都能按照这个标准解析。而 win cmd 可以说是一个私有的东西,不用对接终端,所以要用 winapi 的方法操作
codehz
2021-07-21 21:50:13 +08:00
https://docs.microsoft.com/en-us/windows/console/setconsolemode
用这个设置 ENABLE_VIRTUAL_TERMINAL_PROCESSING 就好了
no1xsyzy
2021-07-22 10:36:34 +08:00
python 下有 colorama.init() 来「包装」 sys.stdout sys.stderr 处理这些问题。
大概 Cargo 也用了类似的道具

@ysc3839 『要程序主动开启』的影响范围好谜

Python 测试代码:
https://gist.github.com/no1xsyzy/58dff1441e6dc6919ba4b7c7e350d2ed
ysc3839
2021-07-22 12:05:35 +08:00
@no1xsyzy 影响范围是整个控制台,也就是说 cmd 开启后,同一控制台下运行的所有程序都会生效。
no1xsyzy
2021-07-22 14:02:57 +08:00
@ysc3839 你可以看一下我给的代码
1. cmd 开启后直接 type 含有 \e[##m 代码的文件有颜色
2. 在里面启动 python,print 出的是豆腐块
3. 运行一下 os.system('') (空命令行)之后再 print 又是有颜色。
4. 无论中间是否进行了 3. 退出 python 还是有颜色。
5. 无关 python 是运行文件还是 REPL 模式
应该是 python 启动初始化中进行了设置,但我不清楚 4. 的来源是什么。
另外,如果是 winpty 这种是否会产生隔离?
另外试了一下,那段代码在 powershell 下第一行仍然是豆腐块。
O5oz6z3
2021-07-22 18:19:59 +08:00
Rust 不懂,不知道有没有人提过 Python 的一个简单 workaround 是 os.system('')。
原理参照:bugs.python.org/msg291732
ysc3839
2021-07-23 15:04:09 +08:00
@no1xsyzy
我自己测试了下,写了个最简单的 C 程序:
#include <stdio.h>
int main()
{
puts("\x1B[0;30;41mTesting");
}

编译后用 cmd 执行,确实不会生效,正如前面 https://bugs.python.org/msg291732 所说 It disables VT mode before starting other programs,是我搞错了。
PowerShell 也是同样的情况。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/790879

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX