PowerShell记录未捕获git输出。

4
我正在编写一个脚本来执行一些git操作,我想使用Start-Transcript来监控它。 但是记录文件中缺少大部分git输出。
我尝试将git输出重定向到Out-HostOut-Default,但都没有效果。
以下是我的代码...
$DateTime = Get-Date -Format "yyyyMMdd_HHmmss"
$TranscriptName = "PSTranscript_$DateTime"

Start-Transcript -Path ".\$TranscriptName.txt"

git --bare clone <GIT_REPO_URL> repo | Out-Default

Stop-Transcript

这是我的控制台输出...

Transcript started, output file is .\PSTranscript_20191119_155424.txt
Cloning into 'repo'...
remote: Counting objects: 58975, done.
remote: Compressing objects: 100% (21457/21457), done.
remote: Total 58975 (delta 43348), reused 51727 (delta 37145)
Receiving objects: 100% (58975/58975), 70.46 MiB | 3.95 MiB/s, done.
Resolving deltas: 100% (43348/43348), done.
Checking out files: 100% (3878/3878), done.
Transcript stopped, output file is .\PSTranscript_20191119_155424.txt

以下是会话记录中捕获的内容,注意一些 git 输出缺失。

**********************
Windows PowerShell transcript start
Start time: 20191119155424
Username: 
RunAs User: 
Configuration Name: 
Machine: 
Host Application: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Process ID: 20644
PSVersion: 5.1.17134.858
PSEdition: Desktop
PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.17134.858
BuildVersion: 10.0.17134.858
CLRVersion: 4.0.30319.42000
WSManStackVersion: 3.0
PSRemotingProtocolVersion: 2.3
SerializationVersion: 1.1.0.1
**********************
Transcript started, output file is .\PSTranscript_20191119_155424.txt
**********************
Windows PowerShell transcript end
End time: 20191119155457
**********************

2
这个链接 https://dev59.com/qabja4cB1Zd3GeqPm9s5#47367768 可能会有所帮助。 - VonC
1
“Start-Transcript”应该捕获所有输出流,但是似乎将“git”命令的输出导入“Out-Default”会导致输出未记录在记录中。 - codewario
1
我已经修改了我的答案,以反映基于GitHub上的这个讨论的结论,即Out-Default永远不应该直接从用户代码中调用。 - mklement0
3个回答

4

没有必要调用Out-Default - 只需直接使用git命令,您的问题就会消失:它的标准输出和标准错误流都将被记录下来。

git默认向标准错误输出状态信息,而误用Out-Default会特别影响标准错误输出,如底部部分所述。

以下示例演示了外部程序的标准输出和标准错误输出都会被捕获并记录在传递中

$file = [IO.Path]::GetTempFileName()

"--- DIRECT OUTPUT ---`n"

Start-Transcript $file

# Execute a command that produces
# both stdout and stderr output.
# Do NOT use Out-Default.
if ($env:OS -eq 'Windows_NT') {  # Windows
  cmd /c 'echo hi & nosuch'
} else {                         # macOS, Linux
  sh -c 'echo hi; nosuch'
}

Stop-Transcript

"`n--- CORE CONTENT OF TRANSCRIPT ---"

# Print the core of the transcript.
((Get-Content -Raw $file) -split '(?m)^\*+\s*$')[2]

Remove-Item $file

在Windows上,您将看到类似以下内容的东西,这表明两个流都已被捕获:
--- DIRECT OUTPUT ---

Transcript started, output file is C:\Users\jdoe\AppData\Local\Temp\tmp342C.tmp
hi
'nosuch' is not recognized as an internal or external command,
operable program or batch file.
Transcript stopped, output file is C:\Users\jdoe\AppData\Local\Temp\tmp342C.tmp

--- CORE CONTENT OF TRANSCRIPT ---

Transcript started, output file is C:\Users\jdoe\AppData\Local\Temp\tmp342C.tmp
hi
'nosuch' is not recognized as an internal or external command,
operable program or batch file.

Out-Default cmdlet的目的:

Out-Default不是用于在用户代码中调用的。

它只能被PowerShell主机应用程序使用,包括PowerShell本身。它使用PowerShell的输出格式系统创建漂亮的输出对象字符串表示,并将它们发送到主机进行显示。

它是一个公共cmdlet的原因是你可以覆盖它以定义一个自定义输出格式器,虽然这种情况很少发生。

覆盖非常简单,只需在会话中定义一个高级Out-Default函数,该函数必须具有相同的参数声明和管道绑定行为。你可以通过一个wrapper (proxy) function来构建这样的函数,正如此答案底部所示。请注意,为了从你的函数产生可见输出,你必须将自定义格式化的字符串发送到原始的Out-Default或使用host APIs打印它们(在最简单的情况下,使用Write-Host)。


缺陷:

尽管不建议使用Out-Default,但你的使用应该仍然是有效的。

虽然对于Out-Default来说这是没有意义的,因为它不应该直接调用,但Out-Host存在同样的问题(截至PowerShell Core 7.0.0-preview.6),而且有合法的原因要调用Out-Host,即显式地仅打印到显示器上(这样做不应影响记录行为)。

具体来说,如果你明确使用Out-Host,则来自外部程序stderr输出意外未被记录在传输中。 (与PowerShell命令相比,该问题不会浮现。)

该问题已在GitHub issue#11134中报告。


4
编辑:我在原始代码中留下了Out-Default的错误。这触发了Out-Default中特别影响stderr的一个错误。删除Out-Default修复了我的脚本,现在成功记录git输出。


@VonC发布了一个非常有用的链接,指引了我正确的方向!

所需要做的就是将值为2>&1GIT_REDIRECT_STDERR环境变量添加到Windows用户环境变量中。

如果您使用Windows,这是一个很棒的PowerShell命令,可以用来添加环境变量。

[System.Environment]::SetEnvironmentVariable("GIT_REDIRECT_STDERR", "2>&1", "User")

以下是我的新成绩单的样子...

**********************
Windows PowerShell transcript start
Start time: 20191119165056
Username: 
RunAs User: 
Configuration Name: 
Machine: 
Host Application: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Process ID: 16440
PSVersion: 5.1.17134.858
PSEdition: Desktop
PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.17134.858
BuildVersion: 10.0.17134.858
CLRVersion: 4.0.30319.42000
WSManStackVersion: 3.0
PSRemotingProtocolVersion: 2.3
SerializationVersion: 1.1.0.1
**********************
Transcript started, output file is .\PSTranscript_20191119_165056.txt
Cloning into bare repository 'repo'...
remote: Counting objects: 58975, done.
remote: Compressing objects: 100% (21457/21457), done.
remote: Total 58975 (delta 43347), reused 51727 (delta 37145)
Receiving objects: 100% (58975/58975), 70.33 MiB | 6.04 MiB/s, done.
Resolving deltas: 100% (43347/43347), done.
**********************
Windows PowerShell transcript end
End time: 20191119165115
**********************

1
感谢!对于我的环境,我必须使用这一行,它应该是功能等同的: $env:GIT_REDIRECT_STDERR = "2>&1" - beeks

2

Start-Transcript 应该可以捕获写入控制台主机的所有内容,无论它写入哪个流。然而,我注意到当我将 git 命令管道传递给 Out-Default 时,我得到的是在控制台上显示的命令输出,但在记录命令输出的转录中却什么也没有。

我无法解释为什么会发生这种情况,但是从克隆命令中移除 | Out-Default,它就可以记录输出到转录中了。


1
感谢您的检查,我一直在阅读并期望Out-Default能够解决问题,但是却遇到了相同的情况。不过,重定向输出似乎确实可以解决问题。 - Zam
这将让我彻底疯掉。我在我的工作站上没有设置,但我仍然会在记录中看到 git 输出,除非我将其导向 Out-Default。我以为可能是使用 ConEmu 作为我的控制台主机的怪癖,但即使使用普通的 powershell.exe,我也得到了相同的行为。 - codewario
2
好的观点。请注意,特别是外部程序的_stderr_输出没有被记录下来,但主要观点确实是没有理由一开始就使用Out-Default - mklement0
我已经修改了我的答案,以反映基于GitHub上的这个讨论的结论,即从用户代码中_永远_不应直接调用Out-Default。因此,Out-Default的行为是一个无关紧要的问题,但同样的问题(从记录中省略stderr输出)也会影响Out-Host,而Out-Host确实有合法的用途。 - mklement0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接