【问题标题】:What's the difference between "Write-Host", "Write-Output", or "[console]::WriteLine"?“Write-Host”、“Write-Output”或“[console]::WriteLine”有什么区别?
【发布时间】:2012-02-04 01:04:03
【问题描述】:

有多种不同的方式来输出消息。通过Write-Host、Write-Output 或[console]::WriteLine 输出内容之间的有效区别是什么?

我还注意到,如果我使用:

write-host "count=" + $count

+ 包含在输出中。为什么?在写出之前,不应该评估表达式以生成单个连接字符串吗?

【问题讨论】:

  • Write-Output 当您发出结果时。 Write-Host 当您发出日志信息时。永远不要使用[console]::writeline()。
  • @JohnL 为什么我们不应该使用 [console]::writeline() ?
  • @Backwards_Dave 因为你有 Write-Host.... 好吧,我可能有一些印象,它显示了一个新的控制台窗口(这是很久以前的事了)。这不会发生,但事实仍然是它不是 powershell 惯用语,[console]::writeline("hello world") 不能做任何事情,Write-Host "hello world" 不能做任何事情。另一个更好的、最近适用的答案是write-host 包装write-information,因此它的数据被放在像write-error 这样的流上,这样你就可以捕获它并在其他地方使用它。 [console]::writeline() 不会这样做

标签: powershell


【解决方案1】:

Write-Output 应该在你想在管道中发送数据时使用,但不一定想在屏幕上显示它。如果没有其他人首先使用它,管道最终会将其写入out-default。

Write-Host 当你想要做相反的事情时应该使用。

[console]::WriteLine 本质上就是Write-Host 在幕后所做的事情。

运行此演示代码并检查结果。

function Test-Output {
    Write-Output "Hello World"
}

function Test-Output2 {
    Write-Host "Hello World" -foreground Green
}

function Receive-Output {
    process { Write-Host $_ -foreground Yellow }
}

#Output piped to another function, not displayed in first.
Test-Output | Receive-Output

#Output not piped to 2nd function, only displayed in first.
Test-Output2 | Receive-Output 

#Pipeline sends to Out-Default at the end.
Test-Output 

您需要将串联操作括在括号中,以便 PowerShell 在标记 Write-Host 的参数列表之前处理串联,或使用字符串插值

write-host ("count=" + $count)
# or
write-host "count=$count"

顺便说一句 - 观看 Jeffrey Snover 的 video 解释管道的工作原理。当我开始学习 PowerShell 时,我发现这是对管道如何工作的最有用的解释。

【讨论】:

  • 在 Azure WebJob [console]::WriteLine 工作,但 Write-Host 将导致错误:Win32 内部错误“句柄无效”0x6 在设置控制台输出缓冲区的字符属性时发生.不要问我为什么。
  • 如果我错了,请纠正我,但我相信 Write-Output 是默认值,例如如果你有一个 PsObject 并且你只是通过这样做 $object 将它吐到屏幕上,它实际上会做与 Write-Output $object 相同的事情。可能值得一提
  • 有新的指导:尽可能避免使用Write-Output。请参阅github.com/PoshCode/PowerShellPracticeAndStyle/issues/… > 仅使用 return 来结束执行。 > 避免写输出 (...)。相反,当您想让输出更清晰时,只需将输出分配给相关命名的变量。并将该变量单独放在一行上以表示显式输出。 > Write-Output -NoEnumerate 在 PowerShell 6 上被破坏,并且已经存在 16 个月或更长时间——没有修复它的计划。总之: > 不要使用写输出——永远。
【解决方案2】:

除了 Andy 提到的之外,还有另一个可能很重要的区别 - write-host 直接写入主机并且不返回任何内容,这意味着您不能将输出重定向到文件。

---- script a.ps1 ----
write-host "hello"

现在在 PowerShell 中运行:

PS> .\a.ps1 > someFile.txt
hello
PS> type someFile.txt
PS>

正如所见,您无法将它们重定向到文件中。对于不小心的人来说,这可能会令人惊讶。

但如果改为使用写入输出,您将获得重定向按预期工作。

【讨论】:

  • 使用 Start-Process Powershell 可以捕获 Write-Host 输出。\a.ps1 -RedirectStandardOutput somefile.txt 不过编码有问题(文件将在 SystemDefaultEncoding 中)。
【解决方案3】:

这是完成等效写入输出的另一种方法。只需将您的字符串放在引号中:

"count=$count"

您可以通过运行此实验来确保它与 Write-Output 一样工作:

"blah blah" > out.txt

Write-Output "blah blah" > out.txt

Write-Host "blah blah" > out.txt

前两个将“blah blah”输出到out.txt,但第三个不会。

“help Write-Output”暗示了这种行为:

此 cmdlet 通常在脚本中用于显示字符串和其他 控制台上的对象。但是,因为默认行为是 在管道末端显示对象,一般不显示 使用 cmdlet 所必需的。

在这种情况下,字符串“count=$count”本身就是管道末端的对象,并被显示出来。

【讨论】:

    【解决方案4】:

    对于Write-Host 的用法,PSScriptAnalyzer 会产生以下诊断信息:

    避免使用Write-Host,因为它可能不适用于所有主机,在没有主机时不起作用,并且(PS 5.0 之前)无法抑制、捕获或重定向。请改用Write-Output、Write-Verbose 或Write-Information。

    有关详细信息,请参阅该规则后面的 documentation。后人摘录:

    除非使用带有Show 动词的命令,否则强烈建议不要使用Write-Host。 Show 动词明确表示“显示在屏幕上,没有其他可能性”。

    带有Show 动词的命令不应用此检查。

    Jeffrey Snover 有一篇博文 Write-Host Considered Harmful,其中他声称 Write-Host 几乎总是错误的做法,因为它会干扰自动化,并在诊断背后提供了更多解释,但以上是一个很好的总结。

    【讨论】:

      【解决方案5】:

      根据我的测试,Write-Output 和 [Console]::WriteLine() 的性能比 Write-Host 好得多。

      根据您需要写出多少文本,这可能很重要。

      如果 Write-Host、Write-Output 和 [Console]::WriteLine() 各 5 次测试的结果如下。

      根据我有限的经验,我发现在处理任何类型的现实世界数据时,我需要放弃 cmdlet 并直接使用较低级别的命令,以便从我的脚本中获得任何不错的性能。

      measure-command {$count = 0; while ($count -lt 1000) { Write-Host "hello"; $count++ }}
      
      1312ms
      1651ms
      1909ms
      1685ms
      1788ms
      
      
      measure-command { $count = 0; while ($count -lt 1000) { Write-Output "hello"; $count++ }}
      
      97ms
      105ms
      94ms
      105ms
      98ms
      
      
      measure-command { $count = 0; while ($count -lt 1000) { [console]::WriteLine("hello"); $count++ }}
      
      158ms
      105ms
      124ms
      99ms
      95ms
      

      【讨论】:

      • Write-Output 和 Write-Host 用途不同,因此比较它们的性能没有意义。是的,直接使用 .NET 类型及其方法更快,但您会错过 PowerShell cmdlet 可以提供的高级功能。 [Console]::WriteLine() 类似于当前案例中的 Write-Host,但并非在所有情况下都有效,因为并非所有 PowerShell 主机都是控制台。
      【解决方案6】:

      关于 [Console]::WriteLine() - 如果您要在 CMD 中使用管道(而不是在 powershell 中),则应该使用它。假设您希望您的 ps1 将大量数据流式传输到标准输出,并使用其他一些实用程序来使用/转换它。如果在脚本中使用 Write-Host 会慢很多。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-04-25
        • 2014-03-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-14
        相关资源
        最近更新 更多