powershell - 执行命令时如何忽略 PowerShell 中的特定错误?
问题描述
我知道ErrorAction
争论,也$ErrorActionPreference
,$Error
和$
。
语境
我想解决的问题是,在运行外部命令(例如 choco 或 git)时,它给出的错误应该是警告甚至不是警告,至少在我的任务上下文中是这样。
由于它们的退出代码,PowerShell 认为该结果在任何意义上都是错误的,例如将红色写入输出等,这在我的任务上下文中是不可取的。
-ErrorAction
我可以使用or来抑制这些命令的错误输出,但是我对以这种特定命令的方式完全消除任何2> $null
错误有一种不好的感觉。
我只想忽略已知的“在这种情况下对我来说不是问题”类型错误。
问题
有没有办法处理命令的错误忽略一些特定的,但通常处理所有其他错误条件?
解决方案
在常规控制台窗口中,在 PowerShell v3 及更高版本中, stderr 行打印就像 stdout 行一样。
这是可取的,因为许多程序使用 stderr 不仅报告真正的错误,而且报告任何非数据,例如状态消息。
Stderr 行(除非重定向 - 见下文)直接通过控制台打印(而 stdout 行被发送到 PowerShell 的成功输出流,它们可以在变量中收集、通过管道发送或使用
>
/重定向>>
)。
遗憾的是,即使在 v5.1中,PowerShell ISE也会以与 PowerShell errors 相同的格式以红色打印 stderr 行。
- 带有 PowerShell 扩展的Visual Studio Code没有这个问题,并且总体上值得迁移,因为所有未来的开发工作都将集中在那里,并且它也适用于跨平台的 PowerShell Core版本。
表现良好的控制台应用程序仅使用其退出代码来表示成功(退出代码
0
)与失败(任何非零退出代码)。PowerShell 将最近调用的控制台应用程序的退出代码保存在其自动$LASTEXITCODE
变量中。作为旁白:
- 通用参数
-ErrorAction
,-ErrorVariable
不能与外部程序一起使用。 - 同样,preference 变量
$ErrorActionPreference
没有任何影响(除了意外,由于这个错误,从 PowerShell v5.1 / PowerShell Core 6.2.0-preview.4 开始)。 try
/catch
不能用于检测和处理外部程序的故障。- 有关 PowerShell 复杂错误处理规则的全面概述,请参阅此 GitHub 文档问题。
- 通用参数
注意:我在下面的示例中使用了以下外部命令,它们产生 1 行 stdout 和 1 行 stderr 输出(请注意,重定向>&2
由 处理cmd
,而不是 PowerShell,因为它在'...'
; 它用于产生标准错误输出):
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 输出以供以后使用,并且仅在出现错误时显示它们:
$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"
}
请注意重定向,它指示 PowerShell 也通过管道(stream ,成功流)
2>&1
发送标准错误行(stream ,错误流)。2
1
在
Where-Object
块中,$_ -is [System.Management.Automation.ErrorRecord]
用于标识stderr行,因为 PowerShell 将此类行包装在该类型的实例中。
或者,您可以在临时文件( )中收集 stderr 输出2>/path/to/tmpfile
,读取其内容,然后将其删除。
这个 GitHub 问题建议引入在变量中收集重定向的 stderr 输出的选项,类似于您如何要求cmdlet通过公共参数在变量中收集错误-ErrorVariable
。
有两个警告:
本质上,通过稍后仅打印 stderr 行,与stdout输出相关的特定上下文可能会丢失。
由于Windows PowerShell v5.1 / PowerShell Core 6.2.0的一个错误,
$ErrorActionPreference = Stop
不能生效,因为一旦收到第一条 stderr 行,2>&1
重定向就会触发脚本终止错误。
如果您想在收到stderr 行时有选择地采取行动:
笔记:
本质上,当您处理这些行时,您还不知道程序最终会报告失败还是成功。
$ErrorActionPreference = 'Stop'
警告也适用于此。
以下示例过滤掉 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." }
推荐阅读
- numpy - 为什么 GPflow 的 Scipy 优化器与使用 tf.function 装饰优化步骤不兼容?
- reactjs - 为什么组件状态更新但视觉效果没有更新?
- python-3.x - 服务器重新启动时代理未自动重新连接到我的 SyncManager 子类
- swift - 从 CoreData FetchRequest 初始化 SwiftUi 视图中的变量
- python - 我有一个关于如何计算数据类型的问题
- git - 为“git am”或“git apply”构建补丁
- python - 使用 PyYaml 解析 yaml 文件?
- javascript - 将一个字符替换/删除到另一个 JS
- python - 我的 QWebEngineView 类没有显示在我的 Windows 中
- python-3.x - python在下一个列表中计算重复项