使用 ANSI/VT100 代码在 PowerShell 控制台中输出彩色文本
Colored text output in PowerShell console using ANSI / VT100 codes
我写了一个程序来打印一个字符串,其中包含 ANSI escape sequences 以使文本着色。但它在默认 Windows 10 控制台中没有按预期工作,如您在屏幕截图中所见。
程序输出以转义序列作为打印字符出现。
如果我通过变量或管道将该字符串提供给 PowerShell,输出将按预期显示(红色文本)。
如何在没有任何解决方法的情况下实现程序打印彩色文本?
这是我的程序源代码 (Haskell) - 但与语言无关,只是为了让您了解转义序列是如何编写的。
main = do
let red = "\ESC[31m"
let reset = "\ESC[39m"
putStrLn $ red ++ "RED" ++ reset
虽然 console windows in Windows 10 支持 VT(虚拟终端)/ANSI 转义序列 原则上, 默认情况下关闭支持.
您有三个选择:
(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
- 打开一个新的控制台window以使更改生效。
- 请参阅下面的注意事项。
(b) 从程序内部激活支持,仅针对该程序(进程),使用调用 SetConsoleMode()
Windows API 函数。
- 查看下面的详细信息。
(c) Ad-hoc 解决方法,来自 PowerShell:管道输出从外部程序到 Out-Host
;例如,.\test.exe | Out-Host
- 查看下面的详细信息。
回复 (一):
registry-based 方法 总是激活 VT 支持 全局 ,即 所有 控制台 windows,不管shell/程序在其中运行什么:
单个可执行文件/shells 仍然可以停用对自己的支持,如果需要,使用方法 (b)。
然而,相反,这意味着任何未明确控制 VT 支持的程序的输出都将受 VT 序列的解释;虽然这通常是可取的,但假设这可能会导致对 意外地 产生具有 VT-like 序列的输出的程序的输出的误解。
注:
虽然是一种允许console-window设置受启动可执行文件/window标题限制的机制,通过[= [HKEY_CURRENT_USR\Console]
的 89=]subkeys,那里似乎不支持 VirtualTerminalLevel
值。
即使是,它也不是 可靠的 解决方案,因为通过 [=89] 打开控制台 window =]快捷方式 文件 (*.lnk
)(例如从“开始”菜单或任务栏)不会遵守这些设置,因为 *.lnk
文件具有内置设置 ;虽然您可以通过 Properties
GUI 对话框修改这些 built-in 设置,但在撰写本文时,VirtualTerminalLevel
设置并未出现在该 GUI 中。
回复 (b):
即使在 C# 中调用 SetConsoleMode()
Windows API function from inside the program (process), as shown here 也很麻烦(由于需要 P/Invoke 声明),并且 可能不是一个选项:
对于使用不支持调用 Windows API 的语言编写的程序。
如果您已有无法修改的可执行文件。
在这种情况下,接下来讨论的选项 (c)(来自 PowerShell)可能适合您。
回复 (c):
PowerShell 在启动时自动激活 VT(虚拟终端)支持自身(在 Windows 10 的最新版本中这适用于 Windows PowerShell 和 PowerShell (Core) 7+) - 但是 确实 不 扩展到外部程序 从 Windows PowerShell(但至少从 7.2.2 开始从 PowerShell(核心)调用时 会 )。
但是,如果您通过 PowerShell 中继 外部程序的输出,VT 序列被 识别;使用 Out-Host
是最简单的方法(Write-Host
也可以):
.\test.exe | Out-Host
注意:仅当您要打印到 控制台 时才使用 Out-Host
;相反,如果您想 捕获 外部程序的输出,只需使用 $capturedOutput = .\test.exe
或者,您可以将调用包含在(...)
中,但是,总是先收集所有输出,然后再转发它。
(.\test.exe)
Character-encoding 警告:Windows 默认情况下,PowerShell 希望外部程序的输出使用 OEM 代码页,如遗留系统区域设置(例如,437
在 US-English 系统上)并反映在 [console]::OutputEncoding
中。
.NET 控制台程序自动遵守该设置,但对于使用不同编码(并且不仅产生纯 ASCII 输出(在 7 位范围内))的非 .NET 程序(例如 Python 脚本),您必须(至少暂时)通过分配给 [console]::OutputEncoding
来指定该编码;例如,对于 UTF-8:
[console]::OutputEncoding = [Text.Encoding]::Utf8
.
请注意,这不仅是 VT-sequences 解决方法所必需的,而且 PowerShell 通常也需要这样才能正确解释 non-ASCII 个字符 .
PowerShell Core (v6+), 不幸的是从 v7.2 开始,仍然默认为 OEM 代码页,但是 should be considered a bug,因为它默认为没有 BOM.
的 UTF-8
感谢用户 mklement0 让我知道 VT 支持不会自动启用。这让我看对了方向,我发现 this helpful post.
所以回答我的问题:添加或设置注册表项
HKCU:\Console - [DWORD] VirtualTerminalLevel = 1
重启控制台即可。
对于 Haskell 具体而言,您需要在 Windows 10.
上调用 hSupportsANSIWithoutEmulation 函数以在您的程序中启用 ANSI 转义序列
我写了一个程序来打印一个字符串,其中包含 ANSI escape sequences 以使文本着色。但它在默认 Windows 10 控制台中没有按预期工作,如您在屏幕截图中所见。
程序输出以转义序列作为打印字符出现。 如果我通过变量或管道将该字符串提供给 PowerShell,输出将按预期显示(红色文本)。
如何在没有任何解决方法的情况下实现程序打印彩色文本?
这是我的程序源代码 (Haskell) - 但与语言无关,只是为了让您了解转义序列是如何编写的。
main = do
let red = "\ESC[31m"
let reset = "\ESC[39m"
putStrLn $ red ++ "RED" ++ reset
虽然 console windows in Windows 10 支持 VT(虚拟终端)/ANSI 转义序列 原则上, 默认情况下关闭支持.
您有三个选择:
(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
- 在 PowerShell 中,您可以以编程方式执行此操作,如下所示:
- 打开一个新的控制台window以使更改生效。
- 请参阅下面的注意事项。
- 简而言之:在注册表项
(b) 从程序内部激活支持,仅针对该程序(进程),使用调用
SetConsoleMode()
Windows API 函数。- 查看下面的详细信息。
(c) Ad-hoc 解决方法,来自 PowerShell:管道输出从外部程序到
Out-Host
;例如,.\test.exe | Out-Host
- 查看下面的详细信息。
回复 (一):
registry-based 方法 总是激活 VT 支持 全局 ,即 所有 控制台 windows,不管shell/程序在其中运行什么:
单个可执行文件/shells 仍然可以停用对自己的支持,如果需要,使用方法 (b)。
然而,相反,这意味着任何未明确控制 VT 支持的程序的输出都将受 VT 序列的解释;虽然这通常是可取的,但假设这可能会导致对 意外地 产生具有 VT-like 序列的输出的程序的输出的误解。
注:
虽然是一种允许console-window设置受启动可执行文件/window标题限制的机制,通过[=
[HKEY_CURRENT_USR\Console]
的 89=]subkeys,那里似乎不支持VirtualTerminalLevel
值。即使是,它也不是 可靠的 解决方案,因为通过 [=89] 打开控制台 window =]快捷方式 文件 (
*.lnk
)(例如从“开始”菜单或任务栏)不会遵守这些设置,因为*.lnk
文件具有内置设置 ;虽然您可以通过Properties
GUI 对话框修改这些 built-in 设置,但在撰写本文时,VirtualTerminalLevel
设置并未出现在该 GUI 中。
回复 (b):
即使在 C# 中调用 SetConsoleMode()
Windows API function from inside the program (process), as shown here 也很麻烦(由于需要 P/Invoke 声明),并且 可能不是一个选项:
对于使用不支持调用 Windows API 的语言编写的程序。
如果您已有无法修改的可执行文件。
在这种情况下,接下来讨论的选项 (c)(来自 PowerShell)可能适合您。
回复 (c):
PowerShell 在启动时自动激活 VT(虚拟终端)支持自身(在 Windows 10 的最新版本中这适用于 Windows PowerShell 和 PowerShell (Core) 7+) - 但是 确实 不 扩展到外部程序 从 Windows PowerShell(但至少从 7.2.2 开始从 PowerShell(核心)调用时 会 )。
但是,如果您通过 PowerShell 中继 外部程序的输出,VT 序列被 识别;使用 Out-Host
是最简单的方法(Write-Host
也可以):
.\test.exe | Out-Host
注意:仅当您要打印到 控制台 时才使用 Out-Host
;相反,如果您想 捕获 外部程序的输出,只需使用 $capturedOutput = .\test.exe
或者,您可以将调用包含在(...)
中,但是,总是先收集所有输出,然后再转发它。
(.\test.exe)
Character-encoding 警告:Windows 默认情况下,PowerShell 希望外部程序的输出使用 OEM 代码页,如遗留系统区域设置(例如,437
在 US-English 系统上)并反映在 [console]::OutputEncoding
中。
.NET 控制台程序自动遵守该设置,但对于使用不同编码(并且不仅产生纯 ASCII 输出(在 7 位范围内))的非 .NET 程序(例如 Python 脚本),您必须(至少暂时)通过分配给 [console]::OutputEncoding
来指定该编码;例如,对于 UTF-8:
[console]::OutputEncoding = [Text.Encoding]::Utf8
.
请注意,这不仅是 VT-sequences 解决方法所必需的,而且 PowerShell 通常也需要这样才能正确解释 non-ASCII 个字符 .
PowerShell Core (v6+), 不幸的是从 v7.2 开始,仍然默认为 OEM 代码页,但是 should be considered a bug,因为它默认为没有 BOM.
的 UTF-8感谢用户 mklement0 让我知道 VT 支持不会自动启用。这让我看对了方向,我发现 this helpful post.
所以回答我的问题:添加或设置注册表项
HKCU:\Console - [DWORD] VirtualTerminalLevel = 1
重启控制台即可。
对于 Haskell 具体而言,您需要在 Windows 10.
上调用 hSupportsANSIWithoutEmulation 函数以在您的程序中启用 ANSI 转义序列