我正在编写一个脚本来从 GitHub 下载几个存储库。这是下载存储库的命令:
git clone "$RepositoryUrl" "$localRepoDirectory"
当我运行此命令时,它会在我想要显示的控制台窗口中显示一些不错的进度信息。
问题是我还希望能够检测下载时是否发生任何错误。我发现这篇关于重定向各种流的帖子,所以我尝试了:
(git clone "$RepositoryUrl" "$localRepoDirectory") 2> $errorLogFilePath
这会将任何错误从 stderr 传输到我的文件,但不再在控制台中显示漂亮的进度信息。
我可以像这样使用 Tee-Object:
(git clone "$RepositoryUrl" "$localRepoDirectory") | Tee-Object -FilePath $errorLogFilePath
而且我仍然得到了不错的进度输出,但是这会将 stdout 传递给文件,而不是 stderr;我只关心检测错误。
有没有一种方法可以存储文件或(最好是)变量中发生的任何错误,同时仍将进度信息通过管道传输到控制台窗口?我有一种感觉,答案可能在于将各种流重定向到其他流中,如本文所述,但我不太确定。
======== 更新 =======
我不确定 git.exe 是否与您的典型可执行文件不同,但我做了更多测试,这就是我发现的:
$output = (git clone "$RepositoryUrl" "$localRepoDirectory")
$output 始终包含文本“正在克隆到 '[localRepoDirectory]'...”,无论命令成功完成还是产生错误。此外,执行此操作时,进度信息仍会写入控制台。这让我认为进度信息不是通过标准输出写入的,而是通过其他流?
如果发生错误,则将错误写入控制台,但使用通常的白色前景色,而不是典型的红色表示错误和黄色表示警告。当从 cmdlet 函数中调用它并且命令失败并出现错误时,错误不会通过函数的 -ErrorVariable(或 -WarningVariable)参数返回(但是,如果我自己执行 Write-Error 并通过 -ErrorVariable 返回)。这让我认为 git.exe 不会写入 stderr,但是当我们这样做时:
(git clone "$RepositoryUrl" "$localRepoDirectory") 2> $errorLogFilePath
错误消息被写入文件,所以这让我认为它确实写入了 stderr。所以现在我很困惑...
======== 更新2 =======
因此,在拜伦的帮助下,我使用新流程尝试了更多解决方案,但仍然无法得到我想要的。使用新进程时,我从来没有将好的进度写入控制台。
我尝试过的三种新方法都使用了这段代码:
$process = New-Object System.Diagnostics.Process
$process.StartInfo.Arguments = "clone ""$RepositoryUrl"" ""$localRepoDirectory"""
$process.StartInfo.UseShellExecute = $false
$process.StartInfo.RedirectStandardOutput = $true
$process.StartInfo.RedirectStandardError = $true
$process.StartInfo.CreateNoWindow = $true
$process.StartInfo.WorkingDirectory = $WORKING_DIRECTORY
$process.StartInfo.FileName = "git"
方法 1 - 在新进程中运行并随后读取输出:
$process.Start()
$process.WaitForExit()
Write-Host Output - $process.StandardOutput.ReadToEnd()
Write-Host Errors - $process.StandardError.ReadToEnd()
方法 2 - 同步获取输出:
$process.Start()
while (!$process.HasExited)
{
Write-Host Output - $process.StandardOutput.ReadToEnd()
Write-Host Error Output - $process.StandardError.ReadToEnd()
Start-Sleep -Seconds 1
}
尽管看起来它会在进程运行时写入输出,但在进程退出之前它不会写入任何内容。
方法 3 - 异步获取输出:
Register-ObjectEvent -InputObject $process -EventName "OutputDataReceived" -Action {Write-Host Output Data - $args[1].Data }
Register-ObjectEvent -InputObject $process -EventName "ErrorDataReceived" -Action { Write-Host Error Data - $args[1].Data }
$process.Start()
$process.BeginOutputReadLine()
$process.BeginErrorReadLine()
while (!$process.HasExited)
{
Start-Sleep -Seconds 1
}
这确实在进程运行时输出数据,这很好,但它仍然没有显示好的进度信息:(