使用 ANSI / VT100 代码在 PowerShell 控制台中输出彩色文本
Posted
技术标签:
【中文标题】使用 ANSI / VT100 代码在 PowerShell 控制台中输出彩色文本【英文标题】:Colored text output in PowerShell console using ANSI / VT100 codes 【发布时间】: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
【问题讨论】:
【参考方案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.
【讨论】:
谢谢,这对我帮助很大。 @Szabolcs 指出你可以使用os.system('color')
见:***.com/questions/287871/…【参考方案2】:
感谢用户 mklement0 让我知道 VT 支持不会自动启用。这让我找到了正确的方向,我找到了this helpful post。
所以回答我的问题:添加或设置注册表项
HKCU:\Console - [DWORD] VirtualTerminalLevel = 1
重新启动控制台,它就可以工作了。
【讨论】:
感谢您深入挖掘 - 我什至没有想到可能存在全局切换,但它非常有意义。我冒昧地将您的发现纳入我的更新答案 - 包括切换开关的编程方式和相关警告 - 以提供全面的答案。【参考方案3】:特别是对于 Haskell,您需要调用 hSupportsANSIWithoutEmulation 函数以在 Windows 10 上的程序中启用 ANSI 转义序列。
【讨论】:
以上是关于使用 ANSI / VT100 代码在 PowerShell 控制台中输出彩色文本的主要内容,如果未能解决你的问题,请参考以下文章
linux使用vi命令错误提示:E558: Terminal entry not found in terminfo 'vt100' not known.