Powershell:异步管道
Powershell: Async Pipeline
我需要将第一个函数的输出用于第二个函数。
第一个函数的输出会逐渐生成,但我希望第二个函数在可用时立即使用它。
你能帮忙吗?我使用 sleep 5 来演示延迟。
下面是代码。
Function Test-Service {
$p = Get-Service | select name, CanStop
foreach($m in $p)
{
$instance = New-Object PSObject -Property @{
Name = $m.name
CanStop = $m.CanStop
}
write-host $instance
sleep 5
}
}
Function Get-Something {
[CmdletBinding()]
Param(
[Parameter(ValueFromPipelineByPropertyName)]
$instance
)
process {
$name = $instance.name
$canstop = $instance.canstop
Write-Host "You passed the parameter $Name $CanStop into the function"
}
}
输出如下:
@{Name=AarSvc_f5f1f38; CanStop=True}
@{Name=AdobeARMservice; CanStop=True}
...
which is the output of the first function "Test-Service". It seems it didn't even received by the Get-Something
谢谢
更新 #1:
查看@mklement0 和@zett42 的反馈后,我意识到我误解了 Write-Host 与 pipleline。
然后我尝试了一个新的例子如下(这是我真实世界的代码)
我根据 $list 在当前目录下创建了很多空的 .tbd 文件。然后我读取列表,获取 x 和 y 位置并将名称、x、y 传递给下一个函数以使用
我运行他们的方式是:
Populate-NextIcon -List $instance| Launch-Test
我希望定期看到屏幕输出,但根本没有输出。这意味着我的“启动测试”功能没有被正确调用。
function Launch-TEST
{
[CmdletBinding()]
Param(
[Parameter(ValueFromPipelineByPropertyName )]
[String]$name,
[Parameter(ValueFromPipelineByPropertyName )]
[int]$x,
[Parameter(ValueFromPipelineByPropertyName )]
[int]$y
)
$prefix = "Launch-"
$message = "${prefix}: Received ${name}"
write-host $message
}
function Populate-NextIcon
{
param ([System.Collections.ArrayList]$list)
while($true)
{
$icons = Get-ChildItem -path .\*.tbd | Sort-Object LastWriteTime
if($icons.count -eq 0)
{
break
}
$t = Get-Date -Format "yyyy_MM_dd_HHmmss"
$icon = $icons[0]
$baseName = $icon.BaseName
Add-Content -Path $icon.FullName -Value $t
$i = $list | where-object {$_.name -eq $baseName}
[PSCustomObject]@{
Name = $i.name
x = $i.x
y = $i.y
}
$sleep = (Get-Content -Path $icon.FullName | Measure-Object -Line).Lines
$sleep = $sleep * 5
sleep $sleep
}
}
如果我运行它作为
填充-NextIcon -List $list
我会得到低于预期的输出:
Name x y
---- - -
AAA_PROD 1300 358
BBB_PROD 2068 250
CCC_PROD 1556 358
但是如果我将它流水线化为
填充-NextIcon -List $instance|启动测试
然后虽然我可以看到这些 .tbd 文件已更新但屏幕上没有输出
似乎第一个函数的输出在某处被阻止了?
如评论中所述,使用 Write-Host
不会产生可以直接在管道中进一步处理的输出。顾名思义,Write-Host
写入主机(也称为信息流),但我们需要写入输出(也称为成功)流。
更惯用的方式是:
Function Test-Service {
$p = Get-Service | select name, CanStop
foreach($m in $p)
{
[PSCustomObject]@{
Name = $m.name
CanStop = $m.CanStop
}
sleep 5
}
}
通过创建一个 [PSCustomObject]
而不将其分配给变量,它将自动作为函数的输出结束。这与 New-Object PSObject -Property ...
类似,但不那么冗长。
在我写的第一句话中,“Write-Host
不产生可以直接 处理的输出”。直接强调 因为可以使您的原始代码像这样工作:
Test-Service 6>&1 | Get-Something
这里的数字6
代表信息流(Write-Host
输出到),数字1
代表成功流。所以我们将信息流重定向到成功流,这实际上将两个流合并为一个。现在函数的输出可以成功传递给Get-Something
.
顺便说一句,这个问题的标题有点令人困惑,因为在正常的管道处理中没有异步的东西。当管道中的每个 cmdlet 处理其输入时,管道的其他部分都没有 运行,脚本的其余部分仅在管道处理完成后继续。
我需要将第一个函数的输出用于第二个函数。 第一个函数的输出会逐渐生成,但我希望第二个函数在可用时立即使用它。 你能帮忙吗?我使用 sleep 5 来演示延迟。 下面是代码。
Function Test-Service {
$p = Get-Service | select name, CanStop
foreach($m in $p)
{
$instance = New-Object PSObject -Property @{
Name = $m.name
CanStop = $m.CanStop
}
write-host $instance
sleep 5
}
}
Function Get-Something {
[CmdletBinding()]
Param(
[Parameter(ValueFromPipelineByPropertyName)]
$instance
)
process {
$name = $instance.name
$canstop = $instance.canstop
Write-Host "You passed the parameter $Name $CanStop into the function"
}
}
输出如下:
@{Name=AarSvc_f5f1f38; CanStop=True} @{Name=AdobeARMservice; CanStop=True} ... which is the output of the first function "Test-Service". It seems it didn't even received by the Get-Something
谢谢
更新 #1: 查看@mklement0 和@zett42 的反馈后,我意识到我误解了 Write-Host 与 pipleline。
然后我尝试了一个新的例子如下(这是我真实世界的代码) 我根据 $list 在当前目录下创建了很多空的 .tbd 文件。然后我读取列表,获取 x 和 y 位置并将名称、x、y 传递给下一个函数以使用 我运行他们的方式是:
Populate-NextIcon -List $instance| Launch-Test
我希望定期看到屏幕输出,但根本没有输出。这意味着我的“启动测试”功能没有被正确调用。
function Launch-TEST
{
[CmdletBinding()]
Param(
[Parameter(ValueFromPipelineByPropertyName )]
[String]$name,
[Parameter(ValueFromPipelineByPropertyName )]
[int]$x,
[Parameter(ValueFromPipelineByPropertyName )]
[int]$y
)
$prefix = "Launch-"
$message = "${prefix}: Received ${name}"
write-host $message
}
function Populate-NextIcon
{
param ([System.Collections.ArrayList]$list)
while($true)
{
$icons = Get-ChildItem -path .\*.tbd | Sort-Object LastWriteTime
if($icons.count -eq 0)
{
break
}
$t = Get-Date -Format "yyyy_MM_dd_HHmmss"
$icon = $icons[0]
$baseName = $icon.BaseName
Add-Content -Path $icon.FullName -Value $t
$i = $list | where-object {$_.name -eq $baseName}
[PSCustomObject]@{
Name = $i.name
x = $i.x
y = $i.y
}
$sleep = (Get-Content -Path $icon.FullName | Measure-Object -Line).Lines
$sleep = $sleep * 5
sleep $sleep
}
}
如果我运行它作为 填充-NextIcon -List $list
我会得到低于预期的输出:
Name x y
---- - -
AAA_PROD 1300 358
BBB_PROD 2068 250
CCC_PROD 1556 358
但是如果我将它流水线化为 填充-NextIcon -List $instance|启动测试
然后虽然我可以看到这些 .tbd 文件已更新但屏幕上没有输出 似乎第一个函数的输出在某处被阻止了?
如评论中所述,使用 Write-Host
不会产生可以直接在管道中进一步处理的输出。顾名思义,Write-Host
写入主机(也称为信息流),但我们需要写入输出(也称为成功)流。
更惯用的方式是:
Function Test-Service {
$p = Get-Service | select name, CanStop
foreach($m in $p)
{
[PSCustomObject]@{
Name = $m.name
CanStop = $m.CanStop
}
sleep 5
}
}
通过创建一个 [PSCustomObject]
而不将其分配给变量,它将自动作为函数的输出结束。这与 New-Object PSObject -Property ...
类似,但不那么冗长。
在我写的第一句话中,“Write-Host
不产生可以直接 处理的输出”。直接强调 因为可以使您的原始代码像这样工作:
Test-Service 6>&1 | Get-Something
这里的数字6
代表信息流(Write-Host
输出到),数字1
代表成功流。所以我们将信息流重定向到成功流,这实际上将两个流合并为一个。现在函数的输出可以成功传递给Get-Something
.
顺便说一句,这个问题的标题有点令人困惑,因为在正常的管道处理中没有异步的东西。当管道中的每个 cmdlet 处理其输入时,管道的其他部分都没有 运行,脚本的其余部分仅在管道处理完成后继续。