调用表达式,并非所有输出都返回到变量



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

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

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

输出

PSObject

返回由调用的命令生成的输出(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问题,这个问题没有答案,使用的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返回整个输出?

感谢

正如我在"PowerShell Capture Git Output"中提到的,在 Git 2.16(2018 年第 1 季度)中,您可以先尝试设置:

set GIT_REDIRECT_STDERR=2>&1

然后在Powershell脚本中,你应该同时获得stdout和stderr输出,

另请参阅dahlbyk/posh-git问题 109 以获取更类似于 Powershell 的示例:

$env:GIT_REDIRECT_STDERR = '2>&1'

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


注意:通常应避免使用Invoke-Expression并且没有理由将其用于调用外部程序:只需直接调用它们并分配给变量:

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

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

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

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

警告:在 7.1 之前的 PowerShell 版本中,如果$ErrorActionPreference = 'Stop'恰好生效,使用2>会意外触发终止错误;GitHub 问题 #4002 中讨论了此问题行为。

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

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

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

  • 能够在变量中单独捕获 stderr 输出是可取的,但是,PowerShell 7.2.x 不支持此功能。按照2>variable:errs的思路添加未来的支持是 GitHub 问题 #4332 的主题。

基于数组的结果对于解析是有利的;例如,找到包含单词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] 这种有问题的Out-String行为在 GitHub 问题 #14444 中进行了讨论。

试试这个(没有IEX)

$x=git fetch --all

相关内容

  • 没有找到相关文章

最新更新