powershell - 使用 ANSI / VT100 代码在 PowerShell 控制台中输出彩色文本
问题描述
我编写了一个打印字符串的程序,其中包含ANSI 转义序列以使文本着色。但正如您在屏幕截图中看到的那样,它在默认的 Windows 10 控制台中无法正常工作。
程序输出与转义序列一起显示为打印字符。如果我通过变量或管道将该字符串提供给 PowerShell,则输出将按预期显示(红色文本)。
如何在没有任何解决方法的情况下实现程序打印彩色文本?
这是我的程序源(Haskell)——但语言不相关,只是为了让您可以看到转义序列是如何编写的。
main = do
let red = "\ESC[31m"
let reset = "\ESC[39m"
putStrLn $ red ++ "RED" ++ reset
解决方案
虽然Windows 10 中的控制台窗口 原则上确实支持 VT(虚拟终端)/ANSI 转义序列,但默认情况下支持关闭。
你有三个选择:
(a)默认情况下,通过注册表持久地全局激活支持,如本 SU 答案中所述。
- 简而言之:在注册表项
[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 中,您可以按如下方式以编程方式执行此操作:
- 打开一个新的控制台窗口以使更改生效。
- 请参阅下面的警告。
- 简而言之:在注册表项
(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 中。*.lnk
Properties
VirtualTerminalLevel
回复(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。
推荐阅读
- python - 如何使用嵌套的 for 循环解决 numba 降低错误?
- maven - Dspace 安装在内核失败
- flask - 无法使用 boto3 和烧瓶上传到 s3
- javascript - 如何在 ng-bootstrap 上使用 NgNav 渲染可滚动的垂直导航?
- javascript - 打字稿:是否可以只为导出类型中的一个键设置状态?
- c# - 如何在c#中对相似值数组进行分组
- swift - 使用 Realm freeze() 方法获取整个 Swift 项目中的对象是否安全?
- reactjs - react-material-ui-carousel 的问题 - 不能在一行中显示三张卡片
- linux - 将用户标签(字符串)分配给 pid?
- mysql - 如何使用 sequelize.js 批量更新记录并忽略某些列