不要在从外部命令写入 stderr 时抛出 PowerShell 异常

pen*_*359 9 git error-handling powershell

当外部命令(例如 git)写入 stderr 时,PowerShell 会生成 NativeCommandError 异常。我想正常地看到输出和标准输出,类似于它在标准 UNIX/Linux 系统上的外观。此脚本需要运行许多本机命令,如果可能,我更喜欢不会给每个命令增加太多混乱和维护的解决方案。

在 Linux 上,可以这样检出分支:

$ git checkout devel
Branch 'devel' set up to track remote branch 'devel' from 'origin'.
Switched to a new branch 'devel'
Run Code Online (Sandbox Code Playgroud)

其中微妙的部分是,无论出于何种原因,最后一行都已写入 stderr。但是,git 的退出状态为零表示它成功了。在 PowerShell 下,我得到了这个:

PS> git checkout devel
Branch 'devel' set up to track remote branch 'devel' from 'origin'.
git : Switched to a new branch 'devel'
At line:1 char:1
+ git checkout devel
+ ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (Switched to a new branch 'devel':String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError
Run Code Online (Sandbox Code Playgroud)

检查$LASTEXITSTATUS,显示为零表示结帐成功。但是,由于 git 的行为是将某些消息写入 stderr,因此它会触发 PowerShell 以注册错误。我可以隐藏消息并手动检查退出状态,但我不想在它们显示时隐藏实际的错误消息。此命令确实避免了异常:

PS> git checkout devel 2>$null
Branch 'devel' set up to track remote branch 'devel' from 'origin'.
Run Code Online (Sandbox Code Playgroud)

并且是 StackOverflow 上的其他答案所建议的,但不是我需要的。我尝试将 stderr 重定向到 stdout,希望 PowerShell 可以看到 stdout 上的所有输出并且不会触发异常,但它仍然会:

git checkout devel 2>&1
Branch 'devel' set up to track remote branch 'devel' from 'origin'.
git : Switched to a new branch 'devel'
At line:1 char:1
+ git checkout devel 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (Switched to a new branch 'devel':String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError
Run Code Online (Sandbox Code Playgroud)

我也尝试过捕获异常,但 try..catch 块似乎没有阻止它:

PS> Try { git checkout devel 2>&1 } catch { echo "There was an error, ignore" }
Branch 'devel' set up to track remote branch 'devel' from 'origin'.
git : Switched to a new branch 'devel'
At line:1 char:7
+ Try { git checkout devel 2>&1 } catch { echo "There was an error, ign ...
+       ~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (Switched to a new branch 'devel':String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError
Run Code Online (Sandbox Code Playgroud)

我只希望本机命令在退出状态非零时导致失败,而不是仅写入 stderr。如何在不完全阻止 stderr 的情况下防止 PowerShell 脚本中的本机命令在写入 stderr 时引发异常?

mkl*_*nt0 5

太长了;博士

PowerShell ISE最简单的解决方法如下(常规控制台或 Visual Studio Code 中不需要)

# Redirect stderr (2) to the success stream (1).
# Doing so wraps stderr lines in [System.Management.Automation.ErrorRecord]
# instances; calling .ToString() on them returns them as normal text.
# CAVEAT: BE SURE THAT $ErrorActionPreference = 'Stop' is NOT IN EFFECT.
git checkout devel 2>&1 | % ToString 
Run Code Online (Sandbox Code Playgroud)

有关其他解决方法,包括通过源流区分行的能力,请参阅此答案

但是,您最好切换到 Visual Studio Code作为开发环境,这从根本上解决了问题 - 见下文。

两点旁白:

  • 您看到的是非终止错误,而不是异常(虽然 .NET 异常是PowerShell 错误处理的基础[System.Management.Automation.ErrorRecord],但它们始终包含在实例中,并且可能会也可能不会中止执行(终止错误与非终止错误))。

  • try/catch不捕获终止错误,仅捕获终止错误;虽然您可以$ErrorActionPreference = 'Stop'预先设置将非终止错误提升为终止错误,但程序的执行(在 ISE 中)将在收到第一个stderr 行时中止。


如果将PowerShell 的使用限制

这些环境的行为符合您的预期:

  • 默认情况下,stderr(标准错误)输出会传递到显示器
  • stderr 行的打印方式与常规行一样。

笔记:

  • 在远程处理后台作业的上下文中,stderr 输出仍会发送到 PowerShell 的错误流

  • 与外部程序一起使用2>还存在其他与主机无关的问题。

请参阅此答案以全面概述所有问题。


Von*_*onC 2

如何防止 PowerShell 脚本中的本机命令在写入 stderr 时抛出异常而不完全阻止 stderr?

您可以使用 Git 2.16+尝试我在“ PowerShell Capture Git Output ”中提到的选项

 set GIT_REDIRECT_STDERR=2>&1
Run Code Online (Sandbox Code Playgroud)

然后检查所有内容是否都写在标准输出中。


zett42在评论中添加:

此处显示的命令适用于批处理脚本。

实际使用的 PowerShell 命令是:

$env:GIT_REDIRECT_STDERR = '2>&1'
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

1291 次

最近记录:

5 年,6 月 前