Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to process the output of a command line-by-line as a stream

Tags:

powershell

Writing SomeCommand | { ... } pipes the entire output of SomeCommand to the code in the braces. Is there a way to "pipe" one line at a time and let the code in the braces process it line by line, without waiting for the whole output to be stored in memory?

Update

[Copied from comment]

SomeCommand is an executable (not a powershell cmdlet) that while running produces some output. It takes some time between the lines that it produces, and I do not want to wait until all the lines are produces to perform some operation on each line

like image 947
Alex Shtof Avatar asked May 25 '14 14:05

Alex Shtof


3 Answers

In order for script block to be able to access pipeline, you need process block inside it: Compare the two:

1, 2, 3 | & {
    process {
        $_
        Start-Sleep -Seconds 1
    }
}

1, 2, 3 | & {
    $input
    Start-Sleep -Seconds 1
}

Obviously, Foreach-Object (mentioned in previous answers) is usually better alternative than using script blocks in situations like this one, but since you asked for script block, script block is what you should also get...

like image 118
BartekB Avatar answered Nov 01 '22 13:11

BartekB


Pipe the output from the (old-style) text stream executable through PowerShell's foreach cmdlet:

ping.exe www.somesite.com | %{$_}

Explanation: % is an alias for Foreach-Object. It cuts up a text stream at the newline characters and emits the lines one after another. Actually, most cmdlets that takes strings as pipe input will just work on the command line (it is actually PowerShell that cuts up the text stream, and not the cmdlets).

like image 3
use Avatar answered Nov 01 '22 11:11

use


In powershell, objects are passed item-by-item along the object pipeline.

A related useful characteristic of pipelines is that because they operate on each item separately, you do not have to modify them based on whether you will have zero, one, or many items in the pipeline. Furthermore, each command in a pipeline (called a pipeline element) usually passes its output to the next command in the pipeline item-by-item. This usually reduces the resource demand of complex commands and allows you to begin getting the output immediately.

From Technet

There are some exceptions, though. Some commands (like Sort-Object), need all input objects to be able to send the result to the next step in the object pipeline.

In your example, You could use the ForEach-Object cmdlet (aliased as %) and use its special $_ variable which represents the current item being processed:

Get-ChildItem $pshome | ForEach-Object -Process {if (!$_.PSIsContainer) {$_.Name; $_.Length / 1024; "" }}

EDIT 2 Since you are calling an executable, powershell will split stdout into lines as it receives them and send each string down the object pipeline. See the answer by @use.

like image 3
bouvierr Avatar answered Nov 01 '22 12:11

bouvierr