我无法弄清楚如何回显标准错误流并重定向可执行文件的错误流。
我来自Bourne shell和Korn shell背景,我将使用它;
# Write to stderr
echo "Error Message!" >&2
# Redirect stderr to file
/do/error 2>/tmp/err.msg
答案 0 :(得分:39)
使用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
。
答案 1 :(得分:31)
你可能想要这个:
$host.ui.WriteErrorLine('I work in any PowerShell host')
您可能还会看到以下内容,但它假定您的PowerShell主机是控制台 窗口/设备,所以我认为它不太有用:
[Console]::Error.WriteLine('I will not work in the PowerShell ISE GUI')
答案 2 :(得分:26)
注意:
当从那里调用PowerShell脚本时,这个答案是关于从外部世界 的角度写入stderr;答案是从 Windows shell cmd.exe
的角度编写的,当与PowerShell结合使用时,它同样适用于 Unix shell,例如bash
芯
相比之下,来自 Powershell 中的,您应该使用Write-Error
,如Keith Hill's answer中所述。
可悲的是,没有统一方法可以在 PowerShell 和中的中使用在外面 - 请参阅我的this answer进行讨论。
添加到@Chris Sear's great answer:
虽然$host.ui.WriteErrorLine
应该在所有主机中都有效,但在通过cmd.exe
调用时(默认情况下)不会写入stderr,例如来自批处理文件。
相比之下, [Console]::Error.WriteLine
总是 。
所以如果你想编写一个PowerShell脚本,在从cmd.exe
调用时在输出流方面很好地发挥作用,请使用以下函数Write-StdErr
,它使用{ {1}}
在常规PS / [Console]::Error.WriteLine
主机(控制台窗口)中,以及cmd.exe
,否则:
$host.ui.WriteErrorLine
在内部,PowerShell比传统输出流(stdout和stderr)更多,并且它们的计数随着时间的推移而增加(以<#
.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")
}
}
为例,并在{{ 3}};请注意,链接页面尚未反映PowerShell v5中引入的Get-Help about_Redirection
的流Write-Warning "I'll go unheard." 3> $null
。
当与外界交互时,PowerShell必须将非传统输出流映射到stdout和stderr。
然而,奇怪的是,PowerShell默认情况下会在调用时将所有的所有流(包括6
和Write-Host
输出)发送到 stdout 来自$host.ui.WriteErrorLine()
,即使将PowerShell的错误流映射到stderr也是合乎逻辑的选择。此行为自(至少)v2起生效,并且从v5.1开始仍然适用(并且由于向后兼容性原因可能不会更改)。
如果您从cmd.exe
调用,则可以使用以下命令进行验证:
cmd.exe
该命令写入所有PowerShell输出流(当您在PowerShell-v5之前的版本上运行时,您将看到与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 v5中引入的)并具有{ {1}}仅将标准输出重定向到Write-Information
(即抑制标准输出; cmd.exe
)。
除了NUL
(来自>NUL
,直接写入stderr)之外,您将看到 no 输出 - 所有PowerShell的流都被发送到stdout。
或许更奇怪的是, 可以捕获PowerShell的错误流,但只能重定向:
如果您将上面的cerr
更改为[Console]::Error.WriteLine()
,那么它将独占PowerShell的错误流和>NUL
输出,这些输出将被抑制;当然,与任何重定向一样,您也可以将其发送到文件。
(如上所述,2>NUL
总是输出到stderr,无论后者是否被重定向。)
提供更具针对性的示例(同样,从$host.ui.WriteErrorLine()
运行):
[Console]::Error.WriteLine()]
以上仅输出cmd.exe
- powershell -noprofile -command "'out'; Write-Error 'err'" 2>NUL
的输出被抑制。
总结:
没有任何(out
)重定向或只使用 stdout 重定向(Write-Error
或cmd.exe
), PowerShell将所有的输出流发送到 stdout 。
使用 stderr 重定向(>...
),PowerShell 有选择地将错误流发送到 stderr (无论stdout是否也被重定向)。
作为推论,以下常见习语不按预期工作:
1>...
正如人们所料,这不会在将 stderr 输出打印到终端时仅将 stdout 发送到文件2>...
;相反,你必须使用
powershell ... >data-output.txt
接下来 PowerShell知道data-output.txt
的重定向并故意调整其行为 。
(从powershell ... >data-output.txt 2>err-output.tmp; type err-output.tmp >&2; del err-output.tmp
控制台中生成彩色输出的PowerShell中也可以看出这一点,同时在将输出重定向到文件时剥离颜色代码。)