如何逐行处理命令的输出作为流

时间:2014-05-25 14:31:08

标签: powershell

SomeCommand | { ... }写入SomeCommandSomeCommand的整个输出传递给大括号中的代码。有没有办法一次“管道”一行,并让括号中的代码逐行处理,而不是等待整个输出存储在内存中?

更新

[从评论中复制]

{{1}}是一个可执行文件(不是PowerShell cmdlet),它在运行时产生一些输出。它产生的线之间需要一些时间,我不想等到产生所有线以在每一行上执行某些操作

3 个答案:

答案 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)。