【问题标题】:Colored text output in PowerShell console using ANSI / VT100 codes使用 ANSI / VT100 代码在 PowerShell 控制台中输出彩色文本
【发布时间】:2019-01-11 19:47:04
【问题描述】:

我编写了一个程序,它打印一个字符串,其中包含ANSI escape sequences 以使文本着色。但正如您在屏幕截图中看到的那样,它在默认的 Windows 10 控制台中无法正常工作。

程序输出与转义序列一起显示为打印字符。 如果我通过变量或管道将该字符串提供给 PowerShell,则输出将按预期显示(红色文本)。

如何在没有任何变通方法的情况下实现程序打印彩色文本?

这是我的程序源代码 (Haskell) - 但语言不相关,只是为了让您可以看到转义序列是如何编写的。

main = do
    let red = "\ESC[31m"
    let reset = "\ESC[39m"
    putStrLn $ red ++ "RED" ++ reset

【问题讨论】:

    标签: powershell ansi windows-console vt100


    【解决方案1】:

    虽然 Windows 10 中的控制台窗口确实支持 VT(虚拟终端)/ANSI 转义序列 原则上,但默认情况下已关闭支持 /em>

    您有三个选择:

    • (a) 通过注册表在默认情况下持续全局激活支持,详见this SU answer

      • 简而言之:在注册表项[HKEY_CURRENT_USER\Console] 中,创建或设置VirtualTerminalLevel DWORD 值为1
        • 在 PowerShell 中,您可以以编程方式执行此操作,如下所示:
          Set-ItemProperty HKCU:\Console VirtualTerminalLevel -Type DWORD 1
        • 来自cmd.exe(也适用于 PowerShell):
          reg add HKCU\Console /v VirtualTerminalLevel /t REG_DWORD /d 1
      • 打开一个新的控制台窗口以使更改生效。
      • 请参阅下面的注意事项。
    • (b) 从您的程序内部激活支持,仅针对该程序(进程),调用SetConsoleMode() Windows API 函数。

      • 请参阅下面的详细信息。
    • (c) 临时解决方法,来自 PowerShell:将外部程序的输出通过管道传输到 Out-Host;例如,.\test.exe | Out-Host

      • 请参阅下面的详细信息。

    回复(a):

    基于注册表的方法总是全局激活 VT 支持,即,对于所有控制台窗口,无论外壳/程序在什么中运行他们:

    • 如果需要,单独的可执行文件/shell 仍然可以使用方法 (b) 停用对自己的支持。

    • 然而,相反,这意味着任何未明确控制 VT 支持的程序的输出都将受到 VT 序列的解释;虽然这通常是可取的,但假设这可能会导致对程序输出的误解,这些程序意外产生具有类似 VT 序列的输出。

    注意:

    • 虽然一种机制允许控制台窗口设置通过[HKEY_CURRENT_USR\Console]子键VirtualTerminalLevel 值由启动可执行文件/窗口标题限定范围那里似乎不支持。

    • 即便如此,它也不是一个强大的解决方案,因为通过快捷方式文件(*.lnk)打开控制台窗口(例如来自开始菜单或任务栏)不会尊重这些设置,因为*.lnk 文件具有内置的设置;虽然您可以通过Properties GUI 对话框修改这些内置设置,但在撰写本文时,VirtualTerminalLevel 设置并未出现在该 GUI 中。


    回复(b):

    从程序(进程)内部调用SetConsoleMode() Windows API 函数,如 here 所示,即使在 C# 中也很麻烦(由于需要 P/Invoke 声明),并且 可能不是一个选项

    • 适用于以不支持调用 Windows API 的语言编写的程序。

    • 如果您有一个无法修改的预先存在的可执行文件。

    在这种情况下,接下来讨论的选项 (c)(来自 PowerShell)可能对您有用。


    回复(c):

    PowerShell 在启动时自动激活 VT(虚拟终端)支持为自己(在 Windows 10 的最新版本中,这适用于 Windows PowerShell 和 PowerShell Core) - 但是扩展到外部程序调用 PowerShell

    但是,如果您通过 PowerShell中继外部程序的输出,则 VT 序列会被识别;使用Out-Host 是最简单的方法(Write-Host 也可以):

    .\test.exe | Out-Host
    

    注意:仅当您要打印到控制台时,才使用Out-Host;相反,如果您想捕获外部程序的输出,只需使用$capturedOutput = .\test.exe

    字符编码警告:默认情况下,Windows PowerShell 期望外部程序的输出使用 OEM 代码页,由旧系统区域设置定义(例如,美国英语系统上的 437)正如[console]::OutputEncoding 所反映的那样。 .NET 控制台程序自动遵守该设置,但对于使用不同编码(并且不仅产生纯 ASCII 输出(在 7 位范围内))的非 .NET 程序(例如 Python 脚本),您必须(至少临时)通过分配给[console]::OutputEncoding来指定编码;例如,对于 UTF-8:
    [console]::OutputEncoding = [Text.Encoding]::Utf8.
    请注意,这不仅是 VT 序列解决方法所必需的,而且 PowerShell 通常需要正确解释非 ASCII 字符

    PowerShell Core (v6+),不幸的是,从 v7.2 开始,它仍然默认为 OEM 代码页,但 should be considered a bug,否则默认为 UTF- 8 没有 BOM.

    【讨论】:

    【解决方案2】:

    感谢用户 mklement0 让我知道 VT 支持不会自动启用。这让我找到了正确的方向,我找到了this helpful post

    所以回答我的问题:添加或设置注册表项

    HKCU:\Console  -  [DWORD] VirtualTerminalLevel = 1
    

    重新启动控制台,它就可以工作了。

    【讨论】:

    • 感谢您深入挖掘 - 我什至没有想到可能存在全局切换,但它非常有意义。我冒昧地将您的发现纳入我的更新答案 - 包括切换开关的编程方式和相关警告 - 以提供全面的答案。
    【解决方案3】:

    特别是对于 Haskell,您需要调用 hSupportsANSIWithoutEmulation 函数以在 Windows 10 上的程序中启用 ANSI 转义序列。

    【讨论】:

      猜你喜欢
      • 2011-11-16
      • 2016-08-03
      • 2020-07-13
      • 1970-01-01
      • 2016-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多