Powershell 管道导致内存使用量爆炸式增长

标签 powershell batch-file

我目前正在 Powershell 中编写一个脚本,允许将 SVN 存储库中的文件夹复制到另一个,同时保留历史记录。此类命令的一个示例是:

svnadmin.exe dump $FromRepoPath `
    | svndumpfilter.exe include --drop-empty-revs --renumber-revs --preserve-revprops $Folder `
    | svnadmin.exe load --ignore-uuid $ToRepoPath

这会导致 Powershell 中的内存使用率非常高。 Powershell 似乎首先执行 svnadmin.exe 并缓冲来自 SVN admin 的 stdout,然后执行 svndumpfilter 和缓冲输出,最后执行 svnadmin.exe。

我可以通过创建一个单独的批处理文件来解决它:
@echo off
svnadmin.exe dump %1 | svndumpfilter.exe include --drop-empty-revs --renumber-revs --preserve-revprops %2 | svnadmin.exe load --ignore-uuid %3

然后从 Powershell 调用它:
cmd.exe /c "SvnHelper.cmd $FromRepoPath $Folder $ToRepoPath"

但这感觉像是一种讨厌且不必要的解决方法。

有没有办法告诉Powershell在管道时直接传递而不是缓冲它?

最佳答案

缓冲的不是输出,而是任何外部进程的输入。您可以使用如下函数验证行为:

function Read-Pipeline {
[cmdletbinding()]
param ([Parameter(Mandatory = $true, ValueFromPipeline=$true)] $inp)
    Begin {}
    Process {Write-Verbose $inp ; Return $inp}
    End {}
}

如果你然后运行:
.\LongRunning.exe | Read-Pipeline -Verbose | .\Other.exe

您将在 Verbose 中看到 LongRunning.exe 的输出,但 Other.exe 在其管道关闭之前不会运行。如果你这样做:
.\LongRunning.exe | Read-Pipeline -Verbose | Write-Host

您将看到没有缓冲的交替 Verbose/Console 输出行,因为输入没有跨越进程边界。

这些都没有真正帮助你。您可以通过回退到 .NET 来启动进程并手动将 STDOUT 复制到 STDIN [1] 来解决这个问题,但它需要大量的工作,但返回很少。最简单的做法是将您的命令传递给 CMD,例如:
& cmd.exe "/C svnadmin.exe dump $FromRepoPath ^| svndumpfilter.exe include --drop-empty-revs --renumber-revs --preserve-revprops $Folder ^| svnadmin.exe load --ignore-uuid $ToRepoPath

[1] http://sushihangover.blogspot.com/2012/01/powershell-piping-standard-output-to.html

关于Powershell 管道导致内存使用量爆炸式增长,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27440768/

相关文章:

batch-file - 带引号的批量 findstr

powershell - 如何在Powershell中使用Pester模拟ErrorRecord?

matlab - 使用 Matlab 将日志语句写入标准输出

string - 通过Windows批处理文件将文件中的字符串 append 到另一个字符串之后

java - 在从批处理文件调用 Java 程序时需要帮助

batch-file - 如何使用批处理脚本从所有用户的桌面上删除文件?

PowerShell版本号比较和前导零

powershell - Try-catch 问题 powershell

email - 如何使用 PowerShell 将文件附加到电子邮件

linux - 在 Windows 上将程序作为(linux 风格)前台终端进程运行?