首页 > 解决方案 > 使用 ANSI / VT100 代码在 PowerShell 控制台中输出彩色文本

问题描述

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

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

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

在此处输入图像描述

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

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

标签: powershellansiwindows-consolevt100

解决方案


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

你有三个选择:

  • (a)默认情况下,通过注册表持久地全局激活支持,如本 SU 答案中所述。

    • 简而言之:在注册表项[HKEY_CURRENT_USER\Console]中,创建或设置VirtualTerminalLevelDWORD 值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)通过调用Windows API 函数从程序内部激活支持,仅针对该程序(进程) 。SetConsoleMode()

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

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

回复(一):

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

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

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

笔记:

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

  • 但是,即使是这样,它也不是一个可靠解决方案,因为通过快捷方式文件*.lnk(他们;虽然您可以通过 GUI 对话框修改这些内置设置,但在撰写本文时,该设置尚未出现在该 GUI 中。*.lnkPropertiesVirtualTerminalLevel


回复(b):

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

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

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

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


回复(c):

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

但是,如果您通过 PowerShell中继外部程序的输出,则可以识别VT 序列;usingOut-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-sequences 变通方法是必需的,而且对于 PowerShell 正确解释非 ASCII 字符通常也是必需的

不幸的是,从 v7.2 开始, PowerShell Core (v6+) 仍然默认为 OEM 代码页,但这应该被视为一个错误,因为它在其他情况下默认为没有 BOM 的 UTF-8


推荐阅读