-
在常规控制台窗口中,在 PowerShell v3 及更高版本中,stderr 行的打印方式与 stdout 行一样。
-
遗憾的是,PowerShell ISE,即使在 v5.1 中,确实以红色打印标准错误行em>,与 与 PowerShell 错误格式相同。
-
带有 PowerShell 扩展的Visual Studio Code 没有这个问题,并且总体上值得迁移到,因为所有未来的开发工作都将集中在那里,并且它也适用于跨平台的 PowerShell Core em> 版。
行为良好的控制台应用程序仅使用其退出代码来表示成功(退出代码0)与失败(任何非零退出代码)。 PowerShell 将最近调用的控制台应用程序的退出代码保存在其自动$LASTEXITCODE 变量中。
-
顺便说一句:
- 公共参数
-ErrorAction 和-ErrorVariable 不能用于外部程序。
- 同样,首选项变量
$ErrorActionPreference 无效(除了意外,由于this bug,自 PowerShell v5.1 / PowerShell Core 6.2.0-preview.4 起)。李>
-
try / catch 不能用于检测和处理外部程序的故障。
- 有关 PowerShell 复杂错误处理规则的全面概述,请参阅 this GitHub docs issue。
注意:我在下面的示例中使用了以下外部命令,它们产生 1 行 stdout 和 1 行 stderr 输出(注意重定向 >&2 由 cmd 处理,而不是 PowerShell,因为它在'...' 内;它用于产生stderr 输出):
cmd /c 'echo stdout & echo stderr >&2'
通过非零退出代码 (exit 1) 发出命令信号失败的变体:
cmd /c 'echo stdout & echo stderr >&2 & exit 1'
因此,通常以下就足够了:
$stdOut = cmd /c 'echo stdout & echo stderr >&2' # std*err* will print to console
if ($LASTEXITCODE -ne 0) { Throw "cmd failed." } # handle error
这会在变量$stdout 中捕获stdout 输出并将stderr 输出传递到控制台。
如果您想为稍后收集标准错误输出并仅在出现错误时显示它们:
$stdErr = @() # initialize array for collecting stderr lines.
# Capture stdout output while collecting stderr output in $stdErr.
$stdOut = cmd /c 'echo stdout & echo stderr >&2 & exit 1' 2>&1 | Where-Object {
$fromStdErr = $_ -is [System.Management.Automation.ErrorRecord]
if ($fromStdErr) { $stdErr += $_.ToString() }
-not $fromStdErr # only output line if it came from stdout
}
# Throw an error, with the collected stderr lines included.
if ($LASTEXITCODE -ne 0) {
Throw "cmd failed with the following message(s): $stdErr"
}
或者,您可以在 临时文件 (2>/path/to/tmpfile) 中收集 stderr 输出,读取其内容并将其删除。
This GitHub issue 建议引入在变量中收集重定向的stderr输出的选项,类似于您如何要求cmdlet通过公共参数收集变量中的错误-ErrorVariable.
有两个注意事项:
如果您想在接收到的 stderr 行有选择地采取行动:
注意:
以下示例过滤掉 stderr 行 stderr1 并将行 stderr2 以红色打印到控制台(仅文本,不像 PowerShell 错误)。
$stdOut = cmd /c 'echo stdout & echo stderr1 >&2 & echo stderr2 >&2' 2>&1 |
ForEach-Object {
if ($_ -is [System.Management.Automation.ErrorRecord]) { # stderr line
$stdErrLine = $_.ToString()
switch -regex ($stdErrLine) {
'stderr1' { break } # ignore, if line contains 'stderr1'
default { Write-Host -ForegroundColor Red $stdErrLine }
}
} else { # stdout line
$_ # pass through
}
}
# Handle error.
if ($LASTEXITCODE -ne 0) { Throw "cmd failed." }