【问题标题】:How to ignore specific error in PowerShell when executing a command?执行命令时如何忽略 PowerShell 中的特定错误?
【发布时间】:2019-02-06 08:45:09
【问题描述】:

我知道ErrorAction 参数,还有$ErrorActionPreference$Error$

上下文

我想解决的问题是,在运行外部命令(例如 choco 或 git)时,它给出的错误应该是警告甚至不是警告,至少在我的任务上下文中是这样。

由于它们的退出代码,PowerShell 认为该结果在任何意义上都是错误,例如将红色写入输出等,这在我的任务上下文中是不可取的。

我可以使用-ErrorAction2> $null 抑制这些命令错误输出,但我对以这种特定命令的方式完全消除任何错误有一种不好的感觉。

我只想忽略已知的“在这种情况下对我来说不是问题”类型错误。

问题

有什么方法可以处理命令的错误忽略某些特定的,但正常处理所有其他错误情况?

【问题讨论】:

  • 您可以使用try/catch 仅捕获(并记录/忽略)特定错误,并允许在其他地方处理所有其他错误。
  • @boxdog: try / catch 不适用于调用外部程序。
  • @boxdog:我试过了,但结论是它在这种情况下不起作用。
  • 是的,正如 mklement0 所说,它不适用于外部命令。我误读了你的问题,但看起来你可能有 JamesC 的解决方案。

标签: powershell error-handling powershell-3.0


【解决方案1】:
  • 在常规控制台窗口中,在 PowerShell v3 及更高版本中,stderr 行的打印方式与 stdout 行一样

    • 这是可取的,因为许多程序使用 stderr 不仅报告真正的错误,还报告任何非数据,例如状态消息

    • Stderr 行(除非重定向 - 见下文)直接通过控制台打印(而 stdout 行被发送到 PowerShell 的成功输出流,它们可以在变量中收集、通过管道发送或使用 @ 重定向987654326@/>>)。

  • 遗憾的是,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 输出(注意重定向 >&2cmd 处理,而不是 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>&1 重定向,它指示PowerShell 也通过管道(流1,成功流)发送stderr 行(流2,错误流)。

  • Where-Object 块中,$_ -is [System.Management.Automation.ErrorRecord] 用于标识 stderr 行,因为 PowerShell 在该类型的实例中包装了这些行。

或者,您可以在 临时文件 (2>/path/to/tmpfile) 中收集 stderr 输出,读取其内容并将其删除。

This GitHub issue 建议引入在变量中收集重定向的stderr输出的选项,类似于您如何要求cmdlet通过公共参数收集变量中的错误-ErrorVariable.

有两个注意事项

  • 本质上,通过稍后仅打印标准错误行,与stdout输出相关的特定上下文可能会丢失。

  • 由于bug as of Windows PowerShell v5.1 / PowerShell Core 6.2.0$ErrorActionPreference = Stop 不能生效,因为2>&1 重定向随后会触发脚本终止错误一旦收到第一条 stderr 行。


如果您想在接收到的 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." }

【讨论】:

  • 很高兴听到这个消息,@g.pickardou。如果部分答案应该更清楚,请告诉我。
【解决方案2】:

我以前用 git 遇到过这种情况,并通过使用 $LASTEXITCODE 解决它。

不确定它是否适用于您的情况,或者是否适用于 choco,因为我没有遇到过问题。

# using git in powershell console sends everything to error stream
# this causes red text when it's not an error which is annoying
# 2>&1 redirects all to stdout, then use exit code to 'direct' output

$git_output = Invoke-Expression "& [git pull etc] 2>&1"

# handle output using exitcode
if ($LASTEXITCODE -ne 0) { throw $git_output }
else { Write-Output $git_output }

【讨论】:

  • 您不需要Invoke-Expression(通常应该避免)来执行所需的重定向;例如,$out = cmd /c 'echo out & echo err >&2' 2>&1。在常规控制台中,在 v3 及更高版本中,传递的 stderr 行not 像 PowerShell 错误一样打印 - 仅在 ISE 中发生。但是,通过按原样回显捕获的合并流 (Write-Output $git_output),任何 stderr 行(即使 $LASTEXITCODE0 也可能存在)然后像 PowerShell 错误一样打印 - 甚至在常规控制台中。
猜你喜欢
  • 2022-01-25
  • 2018-06-20
  • 2015-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-04
相关资源
最近更新 更多