4

我在我的 PowerShell 脚本中使用了一些 GIT 命令。大多数时候我通过调用 GIT 命令Invoke-Expression,例如

  • 可以解析输出,或/和
  • 将输出转发到日志记录方法。

在某些 GIT 命令中,我认识到并非所有输出都通过Invoke-Expression文档状态返回:

输出

PS对象

返回由调用的命令生成的输出(Command 参数的值)。

这是一个例子:

> $x = iex "git fetch --all"
remote: Enumerating objects: 7, done.
remote: Counting objects: 100% (7/7), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 4 (delta 3), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (4/4), done.

内容$x

> $x
Fetching origin
Fetching upstream

所以主要信息不返回$x。我无法想象这git fetch --all是通过stderr(没有意义......)返回主要信息。

我还发现了这个 PowerShell question,没有答案,使用的 PowerShell 版本是 2。

使用的 PowerShell 版本:

> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      6.2.0
PSEdition                      Core
GitCommitId                    6.2.0
OS                             Microsoft Windows 10.0.18362
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

如何强制Invoke-Expression返回整个输出?

谢谢

4

3 回答 3

4

正如我在“ PowerShell Capture Git Output ”中提到的,使用Git 2.16 (Q1 2018),您可以先尝试设置:

set GIT_REDIRECT_STDERR=2>&1

然后在你的 Powershell 脚本中,你应该得到 stdout 和 stderr 输出,

另请参阅dahlbyk/posh-gitissue 109以获取更多类似 Powershell 的示例:

$env:GIT_REDIRECT_STDERR = '2>&1'
于 2019-08-25T16:53:25.520 回答
2

试试这个(没有iex)

$x=git fetch --all
于 2019-08-25T16:47:26.017 回答
2

VonC 的答案特别适用于git,但值得讨论一个通用的解决方案


注意:通常Invoke-Expression应该避免使用它来调用外部程序:只需直接调用它们分配给一个变量:

$capturedStdout = git ... # capture git's stdout output as an array of lines

如前所述,将git状态信息输出到stderr,而数据到 stdout;PowerShell 变量分配仅捕获标准输出输出[1]

要捕获交错的 stdout 和 stderr的组合,就像它会打印到终端一样,您可以使用 redirection2>&1,就像在其他 shell 中一样,将错误流 / stderr ( 2) 合并到 ( >&) 数据输出流(等效于 stdout,1-见about_Redirection):

$combinedOutput = git fetch --all 2>&1 

警告:在 PowerShell 版本到 v7.1 中,如果$ErrorActionPreference = 'Stop'碰巧生效,使用2>意外触发终止错误;GitHub 问题 #4002中讨论了这种有问题的行为。

但是,其他 shell 的行为存在不明显的差异:

  • 输出将是一个数组,而不是单个多行字符串,

    • 注意:从 PowerShell 7.2 开始 - 外部程序输出总是被解释为文本(字符串) - 不支持原始二进制输出;看到这个答案
  • 正如预期的那样,源自stdout的行表示为strings,但源自stderr的行实际上是[System.Management.Automation.ErrorRecord]实例,尽管它们像字符串一样打印,并且在转换为字符串时会复制原始行,例如将结果发送到外部程序时。
    这个答案显示了如何按源流分离捕获的行(假设 stdout 和 stderr 已合并)。

基于数组的结果可能有利于解析;例如,查找包含单词的行unpacking

PS> $combinedOutput -match 'unpacking'
Unpacking objects: 100% (4/4), done.

注意:如果有可能只输出一行,请使用@($combinedOutput) -match 'unpacking'

如果您更喜欢接收单个多行字符串

$combinedOutput = (git fetch --all 2>&1) -join "`n"  # \n (LF); or: [Environment]::NewLine 

如果您不介意尾随换行符作为字符串的一部分,您可以更简单地使用Out-String[2]

$combinedOutput = git fetch --all 2>&1 | Out-String

警告Windows PowerShell中,如果存在 stderr 行,这将无法按预期工作,因为它们呈现为 PowerShell错误记录(此问题已在PowerShell (Core) 6+中修复);跑cmd /c 'echo data & echo err >&2' 2>&1 | Out-String来看问题。使用-join "`n"解决方案来避免问题。


笔记:

  • 像往常一样,无论您使用什么重定向,确定外部程序调用是成功还是失败都应该基于其退出代码,反映在 PowerShell 的自动$LASTEXITCODE变量中:按照惯例(大多数但不是所有程序都遵守),0表示成功以及任何非零值失败(一个值得注意的例外是在成功robocopy案例中使用多个非零退出代码来传达附加信息)。

[1] 有关在 PowerShell 中从外部程序捕获输出的全面信息,请参阅此答案

[2] GitHub 问题 #14444Out-String中讨论了这种有问题的行为。

于 2019-08-25T18:17:10.650 回答