V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Kasumi20
V2EX  ›  Windows

cmd 无法显示带颜色字体

  •  
  •   Kasumi20 · 2021-07-21 16:38:12 +08:00 · 2315 次点击
    这是一个创建于 1217 天前的主题,其中的信息可能已经有所发展或是发生改变。

    WdAdl8.png

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

    PowerShell 正常

    第 1 条附言  ·  2021-07-22 15:35:54 +08:00
    找到了,Cargo 用的是 termcolor 这个库:

    https://github.com/rust-lang/cargo/search?q=termcolor


    这个家伙代码封装的不错:

    https://github.com/BurntSushi/termcolor/issues/21
    12 条回复    2021-07-23 15:04:09 +08:00
    ipwx
        1
    ipwx  
       2021-07-21 16:44:36 +08:00   ❤️ 1
    可能 cargo 有魔法。
    ----

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

    谢谢回复,用的是 https://github.com/mackwic/colored 这个库,有 winapi 的依赖,看了一下好像确实没怎么调用 WinAPI
    ysc3839
        4
    ysc3839  
       2021-07-21 17:52:59 +08:00 via Android
    @ipwx Windows 10 的 conhost 是已经支持 escape sequence 更改颜色的,不过要程序主动开启。
    但是 cmd 是会开启的,所以不应该出现 cmd 有问题但是 PowerShell 没问题的情况。
    用 cargo 没问题说明 cargo 开启了这个功能。
    yolee599
        5
    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
        6
    yolee599  
       2021-07-21 18:29:08 +08:00
    Linux 主要输出到终端,做成一个标准了,无论是 xshell 还是 SecureCRT 都能按照这个标准解析。而 win cmd 可以说是一个私有的东西,不用对接终端,所以要用 winapi 的方法操作
    codehz
        7
    codehz  
       2021-07-21 21:50:13 +08:00   ❤️ 1
    https://docs.microsoft.com/en-us/windows/console/setconsolemode
    用这个设置 ENABLE_VIRTUAL_TERMINAL_PROCESSING 就好了
    no1xsyzy
        8
    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
        9
    ysc3839  
       2021-07-22 12:05:35 +08:00
    @no1xsyzy 影响范围是整个控制台,也就是说 cmd 开启后,同一控制台下运行的所有程序都会生效。
    no1xsyzy
        10
    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
        11
    O5oz6z3  
       2021-07-22 18:19:59 +08:00
    Rust 不懂,不知道有没有人提过 Python 的一个简单 workaround 是 os.system('')。
    原理参照:bugs.python.org/msg291732
    ysc3839
        12
    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 也是同样的情况。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3060 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 14:20 · PVG 22:20 · LAX 06:20 · JFK 09:20
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.