【问题标题】:Usage of Write-Output is very unreliable compared to Write-Host与 Write-Host 相比,Write-Output 的使用非常不可靠
【发布时间】:2019-12-06 20:52:39
【问题描述】:

我被指出了一个问题,如果我希望命令按顺序操作,建议使用 Write-Output over Write-Host(因为 Write-Host 不会将输出放在管道上,而其他命令会这样做,这意味着 Write-主机输出可能发生在管道上的其他命令之前或之后,导致输出非常混乱):command execution ordering inside a PowerShell scriptblock

按照这个建议,我使用 Write-Output 制作了一个简单的函数来模仿 Write-Host 的颜色语法。对于排序,这很有效,因此命令的输出现在是连续的,但是现在使用 Write-Output 的颜色输出很糟糕,因此如果我完全使用任何 BackgroundColor,结果会以非常难看的方式喷洒在屏幕上。 Write-Host 的颜色输出紧密可靠,不会渗入控制台的其他部分,因此使用带有颜色的 Write-Output 会产生一些非常丑陋/笨拙的控制台输出。

在离开该功能之前,我是否需要以某种方式重置 $host.ui,或者任何人都可以提出修改此功能的方法,以使颜色保持在所需区域并且不会流血其他控制台区域?

function Write-Color ($text, $ForegroundColor, $BackgroundColor) {
    $defaultFore = $host.ui.RawUI.ForegroundColor
    $defaultBack = $host.ui.RawUI.BackgroundColor
    if ($ForegroundColor -ne $null) { $host.ui.RawUI.ForegroundColor = $ForegroundColor }
    if ($BackgroundColor -ne $null) { $host.ui.RawUI.BackgroundColor = $BackgroundColor }
    Write-Output $text
    $host.ui.RawUI.ForegroundColor = $defaultFore
    $host.ui.RawUI.BackgroundColor = $defaultBack
}

例如

Write-Color "The dog sat on the couch" -ForegroundColor Red -BackgroundColor White

【问题讨论】:

  • 您被指向了错误的帖子(它仅与您的问题无关 - 请参阅 my recent answer 那里)。对于彩色输出,您确实需要Write-Host,否则您必须在发送到成功流/传递给Write-Output 的输出字符串中嵌入VT(虚拟终端)转义序列,但随后它们变为数据。要解决Write-HostWrite-Output / success-stream 输出之间的排序问题,请参阅stackoverflow.com/a/43691123/45375,但请注意它需要将数据 输出发送到屏幕
  • 非常感谢。如果您将此作为答案发布,我会将其标记为答案。我不喜欢微软制造了这个烂摊子。应该有一些明确的区别:Write-Output / Write-Host,我不清楚 Write-Host 会以这种奇怪的方式行事。这是一种脚本语言,我们应该期望事情是连续的,第 1 行完全完成,然后第 2 行等。我对一些执行其他操作的特殊功能没有问题,但对于大多数人来说,大多数时候,他们只是希望命令 1 在命令 2 之前执行。
  • 我想在过去,我遇到过这种“从不使用-Write-Host-for-no-reason-ever”,但我已经停止使用 PowerShell 很多年了,现在又回来了所以必须再次经历这种痛苦(感谢微软!)。好的,这门语言很棒,它比其他语言更容易分割信息,所以我可以原谅这样的事情,但你有什么建议?我应该a)使用Write-Output(它可怕地无法做背景颜色),还是b)使用Write-Host,如“Write-Host“123”-F Red -B White | Out-Host”,这将保证顺序?
  • 转到上面的第二个链接,我尝试按照建议使用“| Out-Host”。因此,以第一个链接Write-Host '------- 1'; Get-Item / | Select-Object FullName; Write-Host '------- 2' 为例(这是非顺序的!)。因此,我(错误地)将| Out-Host 添加到所有内容中,并认为这可以解决问题。 Write-Host '------- 1' | Out-Host; Get-Item / | Select-Object FullName; Write-Host '------- 2' | Out-Host 这(也是!)非连续的!我很难过...我只想以 sequential 方式可靠地输出颜色。是否可以?我真的很感激这个答案......
  • 您需要将Out-Host应用于non-Write-Host语句; Write-Host 已经写入主机。因此:Write-Host '------- 1'; Get-Item / | Select-Object FullName | Out-Host; Write-Host '------- 2'

标签: powershell colors console


【解决方案1】:

Write-Host 正确的工具来产生(可能是彩色的)for-display输出 - 而不是通过PowerShell的输出数据 em>成功输出流,通过 cmdlet 调用和表达式,(可选地通过显式 Write-Output 调用,但这很少需要)。

This answer 解释说,如果您混合 Write-Host 和成功流输出,在 PowerShell v5+ 中打印到控制台的内容可能会以不同的顺序出现

这是一个 副作用 隐式应用 表格 格式化 situationally异步,以努力收集打印输出前的一些数据,以确定合适的列宽。它仅发生在 (a) 没有预定义格式数据,并且 (b) 具有 4 个或更少属性的输出类型(因为具有更多属性的类型默认为 list 格式)。

讨论有问题的行为in this GitHub issue;虽然仍有解决的希望,但很长一段时间都没有活动。

从 PowerShell 7.0 开始,没有好的解决方案

两种次优的解决方法:

  • (a) 将触发异步行为的单个命令传递给... | Out-Host

    • 例如,在以下命令中,必须将带有 Select-Object 调用的命令发送到 Out-Host 以便正确显示在屏幕上的两个 Write-Host 调用之间

      Write-Host '------- 1'; Get-Item . | Select-Object FullName | Out-Host; Write-Host '------- 2'
      
    • 缺点:使用Out-Host 意味着您无法捕获或重定向命令的输出,因为它直接发送到主机 (显示)。此外,(a) 知道哪些命令会触发问题以及 (b) 记住将解决方法应用于每个命令是很麻烦的。

  • (b) Write-Host 调用替换为发送带有嵌入 VT (Virtual Terminal) escape sequences(用于着色)的字符串到成功输出流

    • 注意:需要 Windows 10 上的 Windows PowerShell v5.1 或 PowerShell [Core] v6+

    • 缺点:(彩色)字符串成为代码数据输出的一部分,因此在您捕获/重定向时被包含输出

      # Windows PowerShell 5.1: [char] 0x1b produces an ESC char.
      $green = [char] 0x1b + '[32m'; $reset = [char] 0x1b + '[m'
      # Print "green" in green.
      "It ain't easy being ${green}green${reset}."
      
      # PowerShell 6+: `e can be used inside "..." for ESC.
      $yellow = "`e[33m"; $reset = "`e[m"
      # Print "yellow" in yellow.
      "They call me mellow ${yellow}yellow${reset}."
      
      • 这些字符串包含 ESC 字符的事实。实际上可以用于从数据流中过滤掉用于显示的字符串(假设您的实际数据不包含 ESC 字符。),沿着 ... | Where-Object { -not ($_ -is [string] -and $_ -match '\e') } 的行

嵌入 VT 转义序列允许您有选择地为字符串的部分着色。

使用Write-Host 实现相同的效果需要多次 调用-NoNewline

第三方 cmdlet(模块)Write-ColoredOutput 模拟Write-Host 的语法并使用[console] 类型的属性来打开和关闭着色,同时将字符串发送到成功输出流.
这适用于以给定颜色编写 整个 字符串,但您不能将不同颜色的部分拼凑在 单行 上,因为每个字符串都单独写入成功输出流总是在自己的行上打印

如果您想要一个将 VT 序列直接嵌入字符串的便捷包装器,您可以调整 Write-HostColored 函数 from this answer,将在幕后发生的 Write-Host 调用替换为 VT 序列。

【讨论】:

    猜你喜欢
    • 2012-02-04
    • 1970-01-01
    • 2020-02-03
    • 2017-01-31
    • 1970-01-01
    • 1970-01-01
    • 2012-03-06
    • 2020-06-18
    • 2015-03-27
    相关资源
    最近更新 更多