微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 Powershell 中创建类 Unix 连续管道的最简单方法

如何解决在 Powershell 中创建类 Unix 连续管道的最简单方法

我有两个程序:

  • emitter.exe - 运行无限循环,并始终在 stdout 上打印一条消息。
  • receiver.exe - 也运行无限循环,等待 stdin 上的消息并处理它们。

在 Unix-line 系统上,我可以运行类似的东西并且一切正常:

$ emitter | receiver

它当然不适用于 PowerShell。 PS首先尝试缓冲整个emitter输出,如果完成,则将其传递给receiver。在我们的例子中,由于两个程序中的无限循环,输出永远不会被传递。

模拟类 Unix 行为的最简单解决方法是什么?

解决方法

我想一种简单的方法是将 emitter.exereceiver.exe 封装在两个指定为管道处理器的 PowerShell 函数中。

这是一个完整的 PowerShell 的简单示例脚本:

function emitter() {
  [CmdletBinding(SupportsShouldProcess=$True)]
  [OutputType([String])] Param ()
  Begin {}
  Process {
    sleep -m 1000
    Write-Output "FIRST" 
    sleep -m 5000
    Write-Output "TWO" 
    sleep -m 4000
    Write-Output "THREE"
  }
  End {}  
}
function receiver() {
  [CmdletBinding(SupportsShouldProcess=$True)]
  [OutputType([String])]
  Param ([Parameter(Mandatory=$true,ValueFromPipeline=$true)][String[]] $msg)
  Begin {
    Write-Host "Start"
  }
  Process {
    Write-Host "Received $msg"
  }
  End {
    Write-Host  "quit"
  }
}
emitter | receiver 

Write-Output 函数中的 emitter ... 替换为对 emitter.exe 的调用,将 Write-Host "Received $msg" 函数中的 receiver 替换为对 {{1 的调用}}。 或者更好的是,将它们作为参数传递给这两个函数。对于接收器,您必须使用 receiver.exe,因为我们需要动态地传输来自发射器的输出。内置的 Powerhell System.Diagnostics.Process 无法完成这项工作,因为它不允许对流程标准输入进行写操作(直到现在我一直在寻找解决方法但没有成功)。

编辑: Start-Process 的输出通过管道传输到 WHERE.EXE 的示例实现:

FINDSTR /C:x

根据您的语言环境,将输出如下内容:

Start
The syntax of this command :
Examples :
    WHERE /R c:\windows *.exe *.dll *.bat
quit

更新

这是一个复杂得多的 PowerShell Cmdlet,可用于菊花链外部命令和/或 PS cmdlet。它还可用于调试您的管道。它允许使用 PowerShell 管道处理进行连续管道处理(例如function emitter() { [CmdletBinding(SupportsShouldProcess=$True)] [OutputType([String])] Param ([String] $cmd) Begin {} Process { & $cmd } End {} } function receiver() { [CmdletBinding(SupportsShouldProcess=$True)] [OutputType([String])] Param ([String] $cmd,[String] $cmdpar,[Parameter(Mandatory=$false,ValueFromPipeline=$true)][String[]] $msg) Begin { $cmdinfo = $(Get-Command $cmd) if (!$cmdinfo) { Write-Host "Failed to find $cmd.." exit; } $fullpath = $cmdinfo.Path $ProcessInfo = New-Object System.Diagnostics.ProcessStartInfo $ProcessInfo.FileName = $fullpath $ProcessInfo.RedirectStandardError = $false $ProcessInfo.RedirectStandardOutput = $false $ProcessInfo.RedirectStandardInput = $true $ProcessInfo.UseShellExecute = $false $ProcessInfo.CreateNoWindow = $false; $ProcessInfo.Arguments = $cmdpar $Process = New-Object System.Diagnostics.Process $Process.StartInfo = $ProcessInfo if ($Process.Start()) { $StreamWriter = $Process.StandardInput; Write-Host "Start" } else { Write-Host "Failed to open $cmd.." exit; } } Process { if ($StreamWriter) { $StreamWriter.WriteLine([String]$msg); $StreamWriter.Flush(); } } End { if ($StreamWriter) { $StreamWriter.Close(); $Process.WaitForExit(); Write-Host "quit" } } } emitter "where.exe" | receiver "findstr.exe" "/C:x" )。与 ping -t 127.0.0.1 | emitter_recevier "more.com" 的等价物相比,它带来了一点性能成本。 事实上,不要尝试使用 cmd.exe 的连续管道。

带有解释注释的代码:

sort.exe

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。