PowerShell 控制台中使用 ANSI/VT100 代码的彩色文本输出 [英] Colored text output in PowerShell console using ANSI / VT100 codes

查看:60
本文介绍了PowerShell 控制台中使用 ANSI/VT100 代码的彩色文本输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我编写了一个打印字符串的程序,其中包含

这是我的程序源代码 (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
    • 打开一个新的控制台窗口以使更改生效.
    • 请参阅下面的注意事项.
  • (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 the VirtualTerminalLevel DWORD value to 1
      • 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
    • Open a new console window for changes to take effect.
    • See caveats below.
  • (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], the VirtualTerminalLevel 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 the Properties GUI dialog, as of this writing the VirtualTerminalLevel 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 代码的彩色文本输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆