如何在PowerShell中写入标准错误?

问题描述 投票:37回答:3

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

我来自Bourne shellKorn shell背景,我会用它;

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

# Redirect stderr to file
/do/error 2>/tmp/err.msg
powershell powershell-v2.0 stderr
3个回答
41
投票

使用Write-Error写入stderr。要将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的缩写(别名)。任何错误都将存储在此参数的参数所指定的变量中。除非我们将错误重定向到$null,否则PowerShell仍会将错误报告给控制台。


31
投票

你可能想要这个:

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

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

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

29
投票

注意:

  • 这个答案是关于从那里调用PowerShell脚本时从外部世界的角度写入stderr;虽然答案是从Windows shell(cmd.exe)的角度编写的,但它与PowerShell Core结合使用时同样适用于bash等Unix shell。
  • 相比之下,在Powershell中,您应该使用Write-Error,如Keith Hill's answer中所述。
  • 遗憾的是,没有统一的方法可以在PowerShell和外部工作 - 请参阅我的this answer进行讨论。

要添加到@Chris Sear's great answer

虽然$host.ui.WriteErrorLine应该在所有主机中工作,但它(默认情况下)在通过cmd.exe调用时不会写入stderr,例如从批处理文件调用。相比之下,[Console]::Error.WriteLine总是如此。

因此,如果您想编写一个从cmd.exe调用时在输出流方面表现良好的PowerShell脚本,请使用以下函数Write-StdErr,它在常规PS / [Console]::Error.WriteLine主机(控制台窗口)中使用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")
  }
}

Optional background information:

在内部,PowerShell比传统的输出流(stdout和stderr)更多,并且它们的数量随着时间的推移而增加(以Write-Warning "I'll go unheard." 3> $null为例,并在Get-Help about_Redirection上阅读更多内容;请注意,链接页面尚未反映6的流Write-Information ,在PowerShell v5中介绍。

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

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

如果从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将stdout仅重定向到NUL(即,压制stdout输出; >NUL)。

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

也许更奇怪的是,有可能捕获PowerShell的错误流,但只能使用重定向:

如果你将>NUL更改为上面的2>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重定向(>...1>...),PowerShell将其所有输出流发送到stdout。
  • 通过stderr重定向(2>...),PowerShell有选择地将其错误流发送到stderr(无论stdout是否也被重定向)。
  • 作为必然结果,以下常见习语不能按预期工作: powershell ... >data-output.txt正如人们所料,这不会发送stdout到文件data-output.txt,同时将stderr输出打印到终端;相反,你必须使用 powershell ... >data-output.txt 2>err-output.tmp; type err-output.tmp >&2; del err-output.tmp

因此,PowerShell意识到cmd.exe的重定向并故意调整其行为。 (这在PowerShell生成cmd.exe控制台中的彩色输出时也很明显,同时在输出重定向到文件时剥离颜色代码。)

© www.soinside.com 2019 - 2024. All rights reserved.