【问题标题】:How do I write to standard error in PowerShell?如何在 PowerShell 中写入标准错误?
【发布时间】:2011-06-27 06:11:30
【问题描述】:

我无法弄清楚如何回显到标准错误流和重定向可执行文件的错误流。

我来自Bourne shellKorn shell 背景,我会使用其中的一个;

# Write to stderr
echo "Error Message!" >&2

# Redirect stderr to file
/do/error 2>/tmp/err.msg

【问题讨论】:

  • 您是在谈论重定向外部可执行文件的输出,它本身是在 powershell 中运行的?
  • 值得注意的是,我发现Write-Error 导致我的脚本终止,因为我使用了$ErrorActionPreference = "Stop",我发现它更有价值。

标签: powershell powershell-2.0 stderr


【解决方案1】:

使用Write-Error 写入标准错误。要将 stderr 重定向到文件使用:

 Write-Error "oops" 2> /temp/err.msg

 exe_that_writes_to_stderr.exe bogus_arg 2> /temp/err.msg

请注意,PowerShell 将错误写入错误记录。如果您想避免错误记录的详细输出,您可以自己写出错误信息,如下所示:

PS> Write-Error "oops" -ev ev 2>$null
PS> $ev[0].exception
oops

-EV-ErrorVariable 的缩写(别名)。任何错误都将存储在此参数的参数命名的变量中。 PowerShell 仍然会向控制台报告错误,除非我们将错误重定向到 $null

【讨论】:

  • 不幸的是,这不是我想要的,我不希望出现堆栈跟踪,我只想用一条错误消息写入错误流。
  • 请记住,PowerShell 是面向对象的,通常推送对象而不是文本。 Write-Error 是您写入错误流的方式。 echo 只是 Write-Object 的兼容性别名,这是您在输出(stdout)流中放置内容的方式。
  • 在您的更新版本中它仍然没有帮助,我希望能够仅将一段文本写入 stderr,这样我就可以有两个重定向 cmd >stdout.log 2>stderr.log。考虑type 内容和管道到stderr 的能力,目前我认为它不能通过外观来完成。
  • 看来Write-Error "oops" -ev ev 2>&1 > $null 没有将任何东西重定向到stderrWrite-Error "oops" 效果很好,但你被冗长的输出卡住了。
  • @OhadSchneider 我不确定你的意思。该命令旨在演示如何“避免”显示 stderr 输出。如果您需要该错误(stderr)信息(但不希望它显示),它可以在 $ev 变量中找到。
【解决方案2】:

你可能想要这个:

$host.ui.WriteErrorLine('I work in any PowerShell host')

您可能还会看到以下内容,但它假定您的 PowerShell 主机是控制台 窗口/设备,所以我认为它不太有用:

[Console]::Error.WriteLine('I will not work in the PowerShell ISE GUI')

【讨论】:

  • WriteErrorLine 是个坏主意。查看文档 (msdn.microsoft.com/en-us/library/…):此方法将一行写入主机的错误显示。 换句话说,这是一个 UI 方法,有时有效如您所料并重定向到标准错误,有时(大多数时候?)没有(见 mklement0 的回答:stackoverflow.com/a/15669365/67824)。正如 Keith Hill 所说,Write-Error 是最好的选择。
【解决方案3】:

注意:

  • 这个答案是关于当从那里调用 PowerShell 脚本时外部世界的角度写入 stderr;虽然答案是从 Windows shell cmd.exe 的角度编写的,但当与 PowerShell Core 结合使用时,它同样适用于 Unix shell,例如 bash。 p>

  • 相比之下, Powershell,您应该使用Write-Error,如Keith Hill's answer 中所述。

  • 遗憾的是,没有统一方法可以在内部 PowerShell 从外部工作 -请参阅我的this answer 进行讨论。


添加到@Chris Sear's great answer

虽然$host.ui.WriteErrorLine 应该适用于所有主机,当通过cmd.exe 调用时,它不会(默认)写入标准错误,例如从批处理文件。 [Console]::Error.WriteLine,相比之下,总是

所以如果您想编写一个 PowerShell 脚本,在从 cmd.exe 调用时可以很好地输出流,请使用以下函数 Write-StdErr,它使用 [Console]::Error.WriteLine 在常规 PS / cmd.exe 主机(控制台窗口)中,$host.ui.WriteErrorLine 否则:

<#
.SYNOPSIS
Writes text to stderr when running in a regular console window,
to the host''s error stream otherwise.

.DESCRIPTION
Writing to true stderr allows you to write a well-behaved CLI
as a PS script that can be invoked from a batch file, for instance.

Note that PS by default sends ALL its streams to *stdout* when invoked from
cmd.exe.

This function acts similarly to Write-Host in that it simply calls
.ToString() on its input; to get the default output format, invoke
it via a pipeline and precede with Out-String.

#>
function Write-StdErr {
  param ([PSObject] $InputObject)
  $outFunc = if ($Host.Name -eq 'ConsoleHost') {
    [Console]::Error.WriteLine
  } else {
    $host.ui.WriteErrorLine
  }
  if ($InputObject) {
    [void] $outFunc.Invoke($InputObject.ToString())
  } else {
    [string[]] $lines = @()
    $Input | % { $lines += $_.ToString() }
    [void] $outFunc.Invoke($lines -join "`r`n")
  }
}

可选背景信息:外部调用者如何看到 PowerShell CLI 的输出流:

在内部,PowerShell 比传统的输出流(stdout 和 stderr)更多,并且它们的数量随着时间的推移而增加(尝试以 Write-Warning "I'll go unheard." 3&gt; $null 为例,并在 Get-Help about_Redirection 阅读更多内容。

在与外界交互时,PowerShell 必须将非传统输出流映射到 stdout 和 stderr。

然而,奇怪的是,当从cmd.exe 调用时,PowerShell 默认将所有 其流(包括Write-Host$host.ui.WriteErrorLine() 输出)发送到stdout ,尽管将 PowerShell 的错误流映射到 stderr 是合乎逻辑的选择。此行为从(至少)v2 开始生效,并且自 v5.1 起仍然适用(并且由于向后兼容性的原因可能不会更改 - 请参阅 GitHub issue #7989)。

您可以使用以下命令验证这一点,如果您从 cmd.exe 调用它

powershell -noprofile -command "'out'; Write-Error 'err'; Write-Warning 'warn'; Write-Verbose -Verbose 'verbose'; $DebugPreference='Continue'; write-debug 'debug'; $InformationPreference='Continue'; Write-Information 'info'; Write-Host 'host'; $host.ui.WriteErrorLine('uierr'); [Console]::Error.WriteLine('cerr')" >NUL

该命令写入所有 PowerShell 输出流(当您在 PowerShell-v5 之前的版本上运行时,您将看到与 Write-Information 相关的附加错误消息,该错误消息是在 PowerShell v5 中引入的)并且具有 cmd.exe仅标准输出重定向到NUL(即抑制标准输出;&gt;NUL)。

除了cerr(来自[Console]::Error.WriteLine(),直接写入stderr)之外,您将看到没有输出-所有PowerShell的流都发送到stdout。

也许更奇怪的是,可以捕获 PowerShell 的错误流,但只能通过重定向

如果您将上面的&gt;NUL 更改为2&gt;NUL,则只会抑制PowerShell 的错误流$host.ui.WriteErrorLine() 输出;当然,与任何重定向一样,您也可以将其发送到文件。 (如上所述,[Console]::Error.WriteLine()] 总是 输出到 stderr,无论后者是否被重定向。)

举一个更有针对性的例子(同样,从cmd.exe运行):

powershell -noprofile -command "'out'; Write-Error 'err'" 2>NUL

上面只输出out - Write-Error的输出被抑制了。

总结

  • 没有任何 (cmd.exe) 重定向或 stdout 重定向(&gt;...1&gt;...),PowerShell 发送所有 它的输出流到stdout

  • 通过 stderr 重定向 (2&gt;...),PowerShell 有选择地 将其 错误流 发送到 stderr (不管标准输出是否也被重定向)。

  • 作为推论,以下常见习语按预期工作:
    powershell ... &gt;data-output.txt 正如人们所期望的那样,这不会在将 stderr 输出打印到终端时仅将 stdout 发送到文件 data-output.txt;相反,您必须使用
    powershell ... &gt;data-output.txt 2&gt;err-output.tmp; type err-output.tmp &gt;&amp;2; del err-output.tmp

因此,PowerShell 知道cmd.exe 的重定向并有意地调整其行为。 (从 PowerShell 在 cmd.exe console 中生成 colored 输出,同时在输出重定向到文件时剥离颜色代码,这一点也很明显。)

【讨论】:

  • 我看到 PS7 将 $Host.UI.WriteErrorLine 输出发送到 stdout 而不是 stderr,即使在 pwsh shell 中调用也是如此。
  • @Marc: Inside PowerShell,没有 stdout 和 stderr 这样的东西,只有 PowerShell 的 6 个流与到主机输出。 PowerShell 之外,$Host.UI.WriteErrorLine - 与Write-Error 一样 - 默认情况下 写入标准输出,但您可以使用2&gt; 重定向它,如答案中所述。要写入外部世界的标准错误默认情况下,请使用[Console]::Error.WriteLine(),按照答案中的建议,以能够在inside PowerShell 会话中捕获此类输出为代价。
  • 我觉得我在逆流而上:PowerShell打算开发人员如何捕获脚本之间的错误输出?我想调用 script.ps1 并捕获错误流/对象。我应该扔吗?无论抛出或写入任何错误,设置-ErrorVariable $foo 似乎对$foo 都没有影响,
  • @Marc:如果命令是高级脚本或函数,或者编译的cmdlet,你只能使用-ErrorVariable,然后你必须使用-ErrorVariable foo - 那也就是说,您不得使用$ sigil
  • 好的,但很奇怪./scriptlet.ps1 2&gt; 没有捕捉到错误,而run-cmdlet 2&gt; 捕捉到了错误。
猜你喜欢
  • 2014-08-27
  • 1970-01-01
  • 1970-01-01
  • 2012-08-11
  • 1970-01-01
  • 2017-06-10
  • 2017-07-21
  • 1970-01-01
相关资源
最近更新 更多