当前位置: 首页 > 知识库问答 >
问题:

从外部命令写入stderr时不要引发PowerShell异常

锺离韬
2023-03-14

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

在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。如何防止PowerShell脚本中的本机命令在不完全阻塞stderr的情况下在写入stderr时引发异常?

共有2个答案

寿高阳
2023-03-14

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

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

 set GIT_REDIRECT_STDERR=2>&1

然后检查所有内容是否都是用stdout编写的。

濮阳驰
2023-03-14

DR

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代码作为开发环境,这样可以从根本上解决问题--请参见下文。

两个方面:

>

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

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

    如果将PowerShell的使用限制为:

    >

  • 终端(控制台),包括即将推出的Windows终端

    带有PowerShell扩展的Visual Studio代码;这个跨平台编辑器(IDE)旨在取代过时的Windows PowerShell ISE。

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

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

    注:

    >

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

    在外部程序中使用2>时,还存在其他与主机无关的问题。

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

  •  类似资料:
    • 问题内容: 我有以下代码,该代码执行外部命令并将两个字段输出到控制台,等待用户输入。一个用于用户名,另一个用于密码,然后我手动添加了它们。 谁能给我一个关于如何写stdin以便从程序内部输入这些输入的提示吗? 对我而言,最棘手的部分是有两个不同的字段在等待输入,而我很难弄清楚如何一个接一个地填充。 解: 问题答案: 我想您可以为此使用a 。像这样: 诀窍是,它只是一个char缓冲区,并且在读取凭据

    • Vim遵循UNIX哲学"做一件事,做好它"。 与其试图集成你可能想要的功能到编辑器自身,更好的办法是在适当时使用Vim来调用外部命令。 让我们在插件中添加一些跟Potion编译器交互的命令,来浅尝在Vim里面调用外部命令的方法。 编译 首先我们将加入一个命令来编译和执行当前Potion文件。 有很多方法可以实现这一点,不过我们暂且用外部命令简单地实现。 在你的插件的repo中创建potion/ft

    • 问题内容: 你如何从Python脚本中调用外部命令(就像我在Unix Shell或Windows命令提示符下键入的一样)? 问题答案: 下面总结了调用外部程序的方法以及每种方法的优缺点: 将命令和参数传递到系统的外壳程序。很好,因为您实际上可以以这种方式一次运行多个命令,并设置管道和输入/输出重定向。例如: 但是,尽管这很方便,但是您必须手动处理外壳字符(例如空格等)的转义。另一方面,这也使您可以

    • 我得到的命令不能识别为内部或外部命令。 我已经重启电脑两次了。

    • 我正试图使用FileWriter将一些文本写入文件。程序运行时不抛出任何异常,除了它应该抛出的异常(写入文件是抛出异常的一部分),但文件保留为空。该文件与包含异常的.java文件和抛出异常的.java文件位于同一目录中。 我正在正确地刷新和关闭FileWriter对象,它位于try/catch块中,该块应该打印代码遇到的任何异常,我尝试使用带有FileWriter作为参数的PrintWriter,

    • 我有办法: 和每个内部事务的另一个bean: 当我第一次尝试保存时,我有20行DB。每次下一次保存,我得到+10行。名称具有约束。当我得到错误时,事务是提交而不是继续。每次保存后我都会等待98行。