如何解决在 Powershell 中创建类 Unix 连续管道的最简单方法
我有两个程序:
-
emitter.exe
- 运行无限循环,并始终在stdout
上打印一条消息。 -
receiver.exe
- 也运行无限循环,等待stdin
上的消息并处理它们。
在 Unix-line 系统上,我可以运行类似的东西并且一切正常:
$ emitter | receiver
它当然不适用于 PowerShell。
PS首先尝试缓冲整个emitter
的输出,如果完成,则将其传递给receiver
。在我们的例子中,由于两个程序中的无限循环,输出永远不会被传递。
模拟类 Unix 行为的最简单解决方法是什么?
解决方法
我想一种简单的方法是将 emitter.exe
和 receiver.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 举报,一经查实,本站将立刻删除。