有没有一种方法可以在PowerShell命令输出中保留ANSI控制代码?

3
在PowerShell中,有没有一种方法可以在将程序输出分配给变量时保留用于向控制台传递颜色信息的ANSI控制代码?
例如,我使用Test Kitchen来提供每个测试套件独特的彩色输出。当我运行"kitchen create INSTANCE"时,我会得到几种颜色的输出。但是,如果我将输出分配给一个变量,或者将其管道传输到另一个cmdlet(如Tee-Object),那么这些颜色信息将会丢失。似乎PowerShell会在结果被发送到管道或分配给变量时剥离这些信息。
kitchen create INSTANCE           # Colored output

$output = kitchen create INSTANCE
Write-Host $output                # Color information is lost

有趣的是,我可以在自己的字符串中实现控制代码,当启用虚拟终端时,PowerShell能够遵守这些代码。与命令输出不同,这些代码可以在变量分配后保留:

$output = "`u{001b}[31mHello"
Write-Host $output                # Results in colored output

看起来只有在程序的输出中,当值被分配或通过管道发送时,颜色信息才会被剥离。是否有办法保留来自外部命令的这些控制代码?


2
我不确定它在PowerShell生态系统中是如何工作的,但在类Unix系统中,通常是命令本身检测输出是否到终端,并关闭颜色控制代码。 - IMSoP
2
PowerShell 不应该受到指责。大多数能够通过 ANSI 转义序列输出彩色文本的工具(外部程序)至少默认情况下会 有选择地 应用颜色,即只有在 stdout 连接到 终端 时(即在打印到显示器时)才会应用颜色。这些工具可能会提供 opt-in 机制,通过命令行选项和/或环境变量来无条件地应用颜色。 - mklement0
根据您的输出量和您想要做什么,也许您可以让输出为自己分配一个标签。例如,[pscustomobject]@{type="error";output=$results} 这样您就可以使用 foreach 循环和 switch/if 语句来处理对象... 如果您只想要输出,您可以执行 write-host $results.output 您甚至可以有一个参数开关,比如 kitchen create instance -colorTag,它可以启用标记功能,但我不确定您的 kitchen 函数/命令是用哪种语言编写的。您可以将 type="error" 改为 color="red"。 - Robert Cotterman
@mklement0 我很担心这个问题。我以TK作为我的例子,尽管它确实有一个提供无条件颜色的选项。然而,正如你所提到的,许多提供彩色输出的实用程序并没有这样做。我希望我至少可以在变量赋值时更改行为,或编写一个模块来帮助保留控制台颜色,以覆盖那些不提供“force-color”选项的实用程序。 - codewario
3个回答

3

除了你自己的回答外,还有以下补充:

  • Windows上,我不知道是否有简单的解决方案,但也许有一种类似于Unix平台下script实用程序所做的程序化方法。

  • 类Unix平台上,您可以使用script实用程序,使外部程序认为它们连接到终端,从而使它们产生彩色输出,否则它们将抑制输出:

    • script不是POSIX规定的实用程序,但至少某些Linux发行版(特别是Ubuntu)以及macOS会提供此实用程序。
    • 值得注意的是,macOS和Linux的实现使用不同的语法,如下所示。

示例:

  • 注意:

    • ls --color=auto被用作一个可用的测试命令,因为它展示了条件着色行为。

    • ls --color=always将展示无条件着色行为,因此可以省略script - 因此,ls是一个允许您请求无条件着色的实用程序的示例;ls --color=auto仅作为不允许无条件着色的实用程序的替代品。

    • 下面的变量赋值($out = ...)用括号(...)括起来,以便通过传递被赋值的值保留着色。

  • Linux

($out = script -qc 'ls --color=auto')
  • 苹果操作系统:
($out = script -q /dev/stdout ls --color=auto)

1
有趣的是,我在Super User上找到了这个答案。我不知道script.exe是否可以独立使用,但该用户报告说它可以从cygwin中移出并独立运行。现在,它是否以与Unix相同的方式处理所有功能是另一回事,但可能值得探究。 - codewario
感谢@BendertheGreatest - 如果你愿意去探究并汇报结果,我很乐意更新答案。尽管如此,安装cygwin似乎需要花费不少精力。 - mklement0
1
如果我有机会探索这个问题,我会这样做。我想象一下,如果它在cygwin中可用,那么可能有一个可用的软件包(例如pacman),可以从中获取该实用程序,如果msys2可以安装相同的工具。 - codewario

2

我正在使用PowerShell v7.3.3,并且尚未在旧版本的7上进行测试。我相当确定这不适用于PowerShell 5,因为它没有$PsStyle。

# Get the current setting so you can flip it back if needed
$OriginalValue = $PsStyle.OutputRendering

# this output should be color coded
$PsStyle.OutputRending = "Ansi"
$String = Get-ChildItem | Select -First 3 | Out-String
Write-Host $String

# this output should not be color coded
$PsStyle.OutputRendering = "Host"
$String = Get-ChildItem | Select -First 3 | Out-String
Write-Host $String

# this should be back to your default/original behavior
$PsStyle.OutputRendering = $OriginalValue
$String = Get-ChildItem | Select -First 3 | Out-String
Write-Host $String

在PS 7.3.6上出现了“在此对象上找不到属性'OutputRending'。请验证该属性是否存在并可设置。”的错误。 - undefined

1
如问题评论中@IMSoP@mklement0所提到的,问题并不在于PowerShell。引用@mklement0的话:
“这里不能怪PowerShell。大多数能够通过ANSI转义序列进行彩色输出的工具(外部程序)至少默认情况下会有选择地应用颜色,即只有当标准输出连接到终端时(即打印到显示器时)才会有颜色。这些实用程序可能会提供选择机制来无条件地应用着色,通过命令行选项和/或环境变量。”

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接