管道流到其他进程

时间:2021-07-21 08:07:00

标签: powershell stream pipe

我想下载一个 20GB 的转储,替换字符串并将其通过管道传输到 mysql.exe,同时它仍在 Powershell 中下载。但是我在传输信息流时遇到了问题。

如果我的文件已经下载,我可以在将文件中的字符串替换为 StdOut 的同时进行流式传输:

Get-Content 'dump.sql' | %{ $_.replace("production_db", "staging_db") }

或者,如果我在流式传输并将字符串替换为 StdOut 时也下载文件,我可以这样做:

$url = 'http://MyServer.ext/dump.sql'
& {
    $myHttpWebRequest = [System.Net.WebRequest]::Create($url)
    $myHttpWebRequest.Headers.Add("Authorization", "Basic " + [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("MyUsername:MyPassword")))
    try {
        $res = $myHttpWebRequest.GetResponse()
    }
    catch [System.Net.WebException] {
        $res = $_.Exception.Response
    } 
    if ([int] $res.StatusCode -ne 200) {
        'Error: ' + [int]$res.StatusCode + " " + $res.StatusCode
    } else {
        $receiveStream = $res.GetResponseStream()
        $encode = [System.Text.Encoding]::GetEncoding("utf-8")
        $readStream = [System.IO.StreamReader]::new($receiveStream, $encode)
        while (-not $readStream.EndOfStream) {
            $readStream.ReadLine().replace("production_db", "staging_db")
        }
        $res.Close()
        $readStream.Close()
    }
}

但在这两种情况下,我都无法将其作为流传输到 mysql.exe。它接缝整个流首先加载到内存中,然后传递给 mysql.exe 进程,当我追加时:

 | & 'C:\Program Files\MySQL\MySQL Server 5.7\bin\mysql.exe' -u MyUsername -pMyPassword -h 127.0.0.1

如何通过管道将流传输到 Powershell 中的另一个进程?

1 个答案:

答案 0 :(得分:0)

我们知道 mysql.exe 将接受标准输入,因为我们可以运行 mysql.exe < myfile.sql 并且它运行良好。我找到了 this 关于将文本行发送到流程的标准输入的绝妙答案,它似乎对我有用。我正在使用 CMD shell 进行测试,因为我手头没有 mysql:

# Setup: example commands to feed via stream to process
'echo "hello"
echo "world"
echo "bye"
exit' > 'C:\temp\file.bat'

# create streamreader from file
$readStream = [System.IO.Streamreader]::new('C:\temp\file.bat')
$encode = [System.Text.Encoding]::GetEncoding("utf-8")

对于您,只需更新您的替代品和 exe 名称:

# Create a process for the job
$psi = New-Object System.Diagnostics.ProcessStartInfo;
$psi.FileName = "cmd.exe"; #process file
$psi.UseShellExecute = $false; #start the process from it's own executable file
$psi.RedirectStandardInput = $true; #enable the process to read from standard input
$psi.RedirectStandardOutput = $true #send standard output to object

$p = [System.Diagnostics.Process]::Start($psi);

# Send each line of the file to the process as standard input:
while (-not $readStream.EndOfStream) {
  $p.StandardInput.WriteLine(
    ($readStream.ReadLine().replace("l", "L"))
  )
}

$readStream.Close()

# Make sure you don't accidentally close mysql before it's done processing.
# For example, add WriteLine('exit') after the While{}, then use Wait-Process.
# get the output of the process, should also wait for the process to finish
$p.StandardOutput.ReadToEnd()
$p.Close() 

在我的测试中,它正在工作,在读取命令时替换它们,并将它们发送到进程,并显示输出:

Microsoft Windows [Version 10.0.19043.1110]
(c) Microsoft Corporation. All rights reserved.

C:\>echo "heLLo"
"heLLo"

C:\>echo "worLd"
"worLd"

C:\>echo "bye"
"bye"

C:\>exit

我认为您应该能够挂钩 $p.StandardOutput 并随时阅读它,但是当我尝试时它会导致进程挂起?也许只是使用 mysql 日志记录代替。