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

问题描述

我编写了一个打印字符串的程序,其中包含 ANSI转义序列使文本变色.但是,如屏幕截图所示,它在默认的Windows 10控制台中无法正常工作.

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.

程序输出与转义序列一起显示为打印字符.如果我通过变量或管道将该字符串提供给PowerShell,则输出将按预期显示(红色文本).

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?

这是我的程序源(Haskell)-但是语言无关,只是为了您可以了解转义序列的编写方式.

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

推荐答案

虽然Windows 10中的控制台窗口确实支持VT(虚拟终端)/ANSI转义序列 原则上 ,默认情况下支持会关闭 .

While console windows in Windows 10 do support VT (Virtual Terminal) / ANSI escape sequences in principle, support is turned OFF by default.

您有三个选择:

  • (a)默认情况下,通过注册表在全球范围内永久性地永久激活支持 ,详情请参见.

  • 简而言之:在注册表项[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
    • In short: In registry key [HKEY_CURRENT_USER\Console], 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 HKCU\Console /v VirtualTerminalLevel /t REG_DWORD /d 1

      (b)通过调用SetConsoleMode() Windows API函数,从程序内部为该程序(进程)激活支持 .

      (b) Activate support from inside your program, for that program (process) only, with a call to the SetConsoleMode() Windows API function.

      • 请参阅下面的详细信息.

      (c)临时解决方法,来自PowerShell :将外部程序的输出通过管道传递到Out-Host;例如.\test.exe | Out-Host

      • 请参阅下面的详细信息.

      基于注册表的方法始终在全局范围内激活 的VT支持,即对于 all 控制台窗口,无论在什么shell/程序中运行他们:

      The registry-based approach invariably activates VT support globally, i.e., for all console windows, irrespective of what shell / program runs in them:

      • 如果需要,单个可执行文件/shell仍然可以使用方法(b)取消对自身的支持.

      • Individual executables / shells can still deactivate support for themselves, if desired, using method (b).

      这意味着,任何未明确控制VT支持的程序的输出都将受VT序列的解释;尽管通常这是理想的,但是假设这可能会导致对偶然产生类似VT序列的输出的程序的输出产生误解.

      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.

      注意:

      • 是一种机制,允许通过[HKEY_CURRENT_USR\Console]子键VirtualTerminalLevel值似乎不受支持.

      • While there is a mechanism that allows console-window settings to be scoped by startup executable / window title, via subkeys of [HKEY_CURRENT_USR\Console], the VirtualTerminalLevel value seems not to be supported there.

      尽管如此,但这也不是一个健壮解决方案,因为它是通过 shortcut 文件(*.lnk)打开控制台窗口的(例如从开始"菜单或任务栏)不会遵守这些设置,因为*.lnk文件具有内置设置;虽然您可以通过Properties GUI对话框修改这些内置设置,但在撰写本文时,VirtualTerminalLevel设置尚未显示在该GUI中.

      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 build 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.

      从程序(进程)内部调用SetConsoleMode() Windows API函数 ,如此处,即使在C#中也很麻烦(由于需要P/Invoke声明),并且可能不是一个选择 :

      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:

      • 用于使用不支持调用Windows API的语言编写的程序.

      • for programs written in languages from which calling the Windows API is not supported.

      ,如果您已有一个无法修改的可执行文件.

      if you have a preexisting executable that you cannot modify.

      如果您不想在这种情况下全局启用支持(选项(a)),则选项(c)(来自PowerShell)可能对您有用.

      If you don't want to enable support globally in that case (option (a)), option (c) (from PowerShell) may work for you.

      PowerShell启动时会自动自动激活VT(虚拟终端)支持 (在Windows 10的最新版本中,这同时适用于Windows PowerShell和PowerShell Core).

      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).

      因此,如果您通过PowerShell 中继外部程序的输出,则可以识别VT序列 ;使用 Out-Host 是最简单的的方式(Write-Host也可以):

      Therefore, 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):

      .\t.exe | Out-Host
      

      注意:仅当您打算打印到控制台时,才使用Out-Host;否则,请使用Out-Host.相反,如果您要捕获外部程序的输出,则仅使用$capturedOutput = .\test.exe

      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 = .\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字符通常也是必需的.

      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 render non-ASCII characters correctly.

      PowerShell Core 也仍然默认为OEM代码页,但是应该被视为 bug ,因为PowerShell Core否则默认为 UTF-8,而没有BOM .

      PowerShell Core, unfortunately, as of v6.1.0-preview.4, still defaults to the OEM code page too, but that should be considered a bug, given that PowerShell Core otherwise defaults to UTF-8 without BOM.

      这篇关于在PowerShell控制台中使用ANSI/VT100代码输出彩色文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-23 19:36