我无法弄清楚如何回显标准错误流并重定向可执行文件的错误流。
我来自Bourne shell和Korn shell背景,我会用它;
# Write to stderr
echo "Error Message!" >&2
# Redirect stderr to file
/do/error 2>/tmp/err.msg
使用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仍会将错误报告给控制台。
你可能想要这个:
$host.ui.WriteErrorLine('I work in any PowerShell host')
您可能还会看到以下内容,但它假设您的PowerShell主机是控制台窗口/设备,因此我认为它不太有用:
[Console]::Error.WriteLine('I will not work in the PowerShell ISE GUI')
注意:
cmd.exe
)的角度编写的,但它与PowerShell Core结合使用时同样适用于bash
等Unix shell。Write-Error
,如Keith Hill's 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")
}
}
在内部,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。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
控制台中的彩色输出时也很明显,同时在输出重定向到文件时剥离颜色代码。)