繁体   English   中英

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

[英]Don't throw PowerShell exception on writes to stderr from external command

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

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

$ git checkout devel
Branch 'devel' set up to track remote branch 'devel' from 'origin'.
Switched to a new branch 'devel'

其中微妙的部分是,无论出于何种原因,最后一行都被写入了 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

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

PS> git checkout devel 2>$null
Branch 'devel' set up to track remote branch 'devel' from 'origin'.

并且是 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

我也尝试过捕获异常,但是 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

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

tl;博士

在PowerShell ISE中最简单的解决方法是以下(不需要在常规控制台或在Visual Studio代码):

# 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 

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

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

两个旁白:

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

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


如果您只PowerShell中使用的话,可以避免这个问题

这些环境的行为与您预期的一样:

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

笔记:

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

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

有关所有问题的全面概述,请参阅此答案

如何在不完全阻止 stderr 的情况下防止 PowerShell 脚本中的本机命令在写入 stderr 时引发异常?

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

 set GIT_REDIRECT_STDERR=2>&1

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

我通常将所有输出重定向到同一个目的地:

Invoke-Command -ScriptBlock {get-module} *>&1 

或者有时我把它扔到一个文件中:

$scriptblock = {
    get-module
}
Invoke-Command -ScriptBlock $scriptblock *>&1 >> file.txt

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM