问题描述
我编写了一个打印字符串的程序,其中包含
这是我的程序源代码 (Haskell) - 但语言不相关,只是为了让您看到转义序列是如何编写的.
main = 做让红色 = "ESC[31m"让重置 = "ESC[39m"putStrLn $ red ++ "RED" ++ 重置
虽然 Windows 10 中的控制台窗口确实支持 VT(虚拟终端)/ANSI 转义序列 原则上, 支持默认关闭.
您有三个选择:
(a) 默认情况下通过注册表在全球范围内持续激活支持,详情请参见这个 SU 答案.
- 简而言之:在注册表项
[HKEY_CURRENT_USERConsole]
中,创建或设置VirtualTerminalLevel
DWORD 值为1
- 在 PowerShell 中,您可以以编程方式执行此操作,如下所示:
Set-ItemProperty HKCU:Console VirtualTerminalLevel -Type DWORD 1
- 来自
cmd.exe
(也适用于 PowerShell):reg add HKCUConsole/v VirtualTerminalLevel/t REG_DWORD/d 1
- 在 PowerShell 中,您可以以编程方式执行此操作,如下所示:
- 打开一个新的控制台窗口以使更改生效.
- 请参阅下面的注意事项.
- 简而言之:在注册表项
(b) 从您的程序内部激活支持,仅针对该程序(进程),调用
SetConsoleMode()
Windows API 函数.- 查看下面的详细信息.
(c) 临时解决方法,来自 PowerShell:将外部程序的输出通过管道传输到
Out-Host
;例如,.est.exe |外主机
- 查看下面的详细信息.
回复 (a):
基于注册表的方法总是全局激活 VT 支持,即对于所有控制台窗口,无论在什么外壳/程序中运行他们:
如果需要,单个可执行文件/shell 仍然可以使用方法 (b) 停用对自身的支持.
然而,相反,这意味着任何未明确控制 VT 支持的程序的输出都将受到对 VT 序列的解释;虽然这通常是可取的,但假设这可能导致对意外产生类似 VT 序列的输出的程序的输出的误解.
注意:
虽然有一种机制,允许通过
[HKEY_CURRENT_USR控制台]
,那里似乎不支持VirtualTerminalLevel
值.即使是这样,它也不是一个健壮的解决方案,因为通过一个快捷方式文件(
*.lnk
)(例如从开始菜单或任务栏)不会尊重这些设置,因为*.lnk
文件具有内置的设置;虽然您可以通过Properties
GUI 对话框修改这些内置设置,但在撰写本文时,VirtualTerminalLevel
设置并未出现在该 GUI 中.
回复 (b):
从程序(进程)内部调用SetConsoleMode()
Windows API 函数,如此处,即使在 C# 中也很麻烦(由于需要 P/Invoke 声明),并且 可能不是一种选择:
用于使用不支持调用 Windows API 的语言编写的程序.
如果您有一个无法修改的预先存在的可执行文件.
如果您不想在这种情况下全局启用支持(选项 (a)),选项 (c)(来自 PowerShell)可能适合您.
回复 (c):
PowerShell 在启动时自动激活对自身的 VT(虚拟终端)支持(在最近的 Windows 10 版本中,这适用于 Windows PowerShell 和 PowerShell Core) - 但是不会扩展到从PowerShell调用的外部程序.
但是,如果你中继一个外部程序的输出通过PowerShell,VT序列被识别;使用 Out-Host
是最简单的方法(Write-Host
也可以):
. .exe |外主机
注意:仅当您要打印到控制台时才使用Out-Host
;相反,如果您想捕获外部程序的输出,只需使用 $capturedOutput = .est.exe
字符编码警告:默认情况下,Windows PowerShell 希望外部程序的输出使用 OEM 代码页,如旧系统区域设置(例如,437
on美国-英语系统)并反映在 [console]::OutputEncoding
中..NET 控制台程序会自动遵守该设置,但对于使用不同编码(并且不仅产生纯 ASCII 输出(在 7 位范围内))的非 .NET 程序(例如 Python 脚本),您必须(至少临时)通过分配给 [console]::OutputEncoding
来指定编码;例如,对于 UTF-8:[控制台]::OutputEncoding = [Text.Encoding]::Utf8
.
请注意,这不仅对于 VT 序列变通方法是必需的,而且对于 PowerShell 正确解释非 ASCII 字符通常也是必需的.
PowerShell Core (v6+),不幸的是,从 v7.2 开始,仍然默认为 OEM 代码页,但是 应该被视为一个bug,因为它默认为UTF-8 without BOM.
I wrote a program which prints a string, which contains ANSI escape sequences to make the text colored. But it doesn't work as expected in the default Windows 10 console, as you can see in the screenshot.
The program output appears with the escape sequences as printed characters.If I feed that string to PowerShell via a variable or piping, the output appears as intended (red text).
How can I achieve that the program prints colored text without any workarounds?
This is my program source (Haskell) - but the language is not relevant, just so you can see how the escape sequences are written.
main = do
let red = "ESC[31m"
let reset = "ESC[39m"
putStrLn $ red ++ "RED" ++ reset
While console windows in Windows 10 do support VT (Virtual Terminal) / ANSI escape sequences in principle, support is turned OFF by default.
You have three options:
(a) Activate support globally by default, persistently, via the registry, as detailed in this SU answer.
- In short: In registry key
[HKEY_CURRENT_USERConsole]
, create or set theVirtualTerminalLevel
DWORD value to1
- From PowerShell, you can do this programmatically as follows:
Set-ItemProperty HKCU:Console VirtualTerminalLevel -Type DWORD 1
- From
cmd.exe
(also works from PowerShell):reg add HKCUConsole /v VirtualTerminalLevel /t REG_DWORD /d 1
- From PowerShell, you can do this programmatically as follows:
- Open a new console window for changes to take effect.
- See caveats below.
- In short: In registry key
(b) Activate support from inside your program, for that program (process) only, with a call to the
SetConsoleMode()
Windows API function.- See details below.
(c) Ad-hoc workaround, from PowerShell: pipe output from external programs to
Out-Host
; e.g.,.est.exe | Out-Host
- See details below.
Re (a):
The registry-based approach invariably activates VT support globally, i.e., for all console windows, irrespective of what shell / program runs in them:
Individual executables / shells can still deactivate support for themselves, if desired, using method (b).
Conversely, however, this means that the output of any program that doesn't explicitly control VT support will be subject to interpretation of VT sequences; while this is generally desirable, hypothetically this could lead to misinterpretation of output from programs that accidentally produce output with VT-like sequences.
Note:
While there is a mechanism that allows console-window settings to be scoped by startup executable / window title, via subkeys of
[HKEY_CURRENT_USRConsole]
, theVirtualTerminalLevel
value seems not to be supported there.Even if it were, however, it wouldn't be a robust solution, because opening a console window via a shortcut file (
*.lnk
) (e.g. from the Start Menu or Task Bar) wouldn't respect these settings, because*.lnk
files have settings built into them; while you can modify these built-in settings via theProperties
GUI dialog, as of this writing theVirtualTerminalLevel
setting is not surfaced in that GUI.
Re (b):
Calling the SetConsoleMode()
Windows API function from inside the program (process), as described here, is cumbersome even in C# (due to requiring a P/Invoke declaration), and may not be an option:
for programs written in languages from which calling the Windows API is not supported.
if you have a preexisting executable that you cannot modify.
If you don't want to enable support globally in that case (option (a)), option (c) (from PowerShell) may work for you.
Re (c):
PowerShell automatically activates VT (virtual terminal) support for itself when it starts (in recent releases of Windows 10 this applies to both Windows PowerShell and PowerShell Core) - but that does not extend to external programs called from PowerShell.
However, if you relay an external program's output via PowerShell, VT sequences are recognized; using Out-Host
is the simplest way to do that (Write-Host
would work too):
. .exe | Out-Host
Note: Use Out-Host
only if you mean to print to the console; if, by contrast, you want to capture the external program's output, use just $capturedOutput = .est.exe
Character-encoding caveat: Windows PowerShell by default expects output from external programs to use the OEM code page, as defined by the legacy system locale (e.g., 437
on US-English systems) and as reflected in [console]::OutputEncoding
..NET console programs respect that setting automatically, but for non-.NET programs (e.g., Python scripts) that use a different encoding (and produce not just pure ASCII output (in the 7-bit range)), you must (at least temporarily) specify that encoding by assigning to [console]::OutputEncoding
; e.g., for UTF-8:[console]::OutputEncoding = [Text.Encoding]::Utf8
.
Note that this is not only necessary for the VT-sequences workaround, but generally necessary for PowerShell to interpret non-ASCII characters correctly.
PowerShell Core (v6+), unfortunately, as of v7.2, still defaults to the OEM code page too, but that should be considered a bug, given that it otherwise defaults to UTF-8 without BOM.
这篇关于PowerShell 控制台中使用 ANSI/VT100 代码的彩色文本输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!