将SomeCommand | { ... }
写入SomeCommand
将SomeCommand
的整个输出传递给大括号中的代码。有没有办法一次“管道”一行,并让括号中的代码逐行处理,而不是等待整个输出存储在内存中?
更新
[从评论中复制]
{{1}}是一个可执行文件(不是PowerShell cmdlet),它在运行时产生一些输出。它产生的线之间需要一些时间,我不想等到产生所有线以在每一行上执行某些操作
答案 0 :(得分:2)
为了使脚本块能够访问管道,您需要其中的进程块: 比较两者:
1, 2, 3 | & {
process {
$_
Start-Sleep -Seconds 1
}
}
1, 2, 3 | & {
$input
Start-Sleep -Seconds 1
}
显然,Foreach-Object
(在之前的答案中提到)通常比在这种情况下使用脚本块更好,但是既然你要求脚本块,脚本块就是你应该得到的...... < / p>
答案 1 :(得分:1)
在powershell中,对象沿对象管道逐项传递。
管道的一个相关有用特性是,因为它们分别对每个项目进行操作,所以您不必根据管道中是否有零个,一个或多个项目来修改它们。此外,管道中的每个命令(称为管道元素)通常将其输出传递到逐个项目的管道中的下一个命令。这通常会减少复杂命令的资源需求,并允许您立即开始获取输出。
来自Technet
但也有一些例外。某些命令(如Sort-Object
)需要所有输入对象能够将结果发送到对象管道中的下一步。
在您的示例中,您可以使用ForEach-Object cmdlet(别名为%
)并使用其特殊的$_
变量来表示当前正在处理的项目:
Get-ChildItem $pshome | ForEach-Object -Process {if (!$_.PSIsContainer) {$_.Name; $_.Length / 1024; "" }}
修改强>
从您的评论中,现在很清楚您正在调用另一个可执行文件来获取其标准输出。我不知道任何内置的cmdlet来调用可执行文件并逐行读取它的输出并将其传递给PowerShell对象管道。但是,如果您创建System.Diagnostics.Process
对象,则每次可执行文件输出新行时,都可以使用Process.BeginOutputReadLine引发Process.OutputDataReceived
事件。请参阅这个伟大的answer作为示例。
使用这种技术,一旦可用,就可以相对容易地处理每个输出线。只需将自定义处理程序挂钩到Process.OutputDataReceived
事件。
答案 2 :(得分:1)
通过PowerShell的foreach
cmdlet管道(旧式)文本流可执行文件的输出:
ping.exe www.somesite.com | %{$_}
说明:%
是Foreach-Object的别名。它会在换行符处剪切文本流并一个接一个地发出这些行。实际上,大多数将字符串作为管道输入的cmdlet只能在命令行上运行(它实际上是PowerShell,它会切断文本流,而不是cmdlet)。