Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Powershell: how do you read & write I/O within one pipeline?

I'd like to be able to type quick, simple commands that manipulate files in-place. For example:

# prettify an XML file
format-xml foo | out-file foo

This won't work because the pipeline is designed to be "greedy." The downstream cmdlet acquires a Write lock to the file as soon as the upstream cmdlet processes the first line of input, which stalls the upstream cmdlet from reading the rest of the file.

There are many possible workarounds: write to temporary files, separate operations into multiple pipelines (storing intermediate results in variables), or similar. But I figure this is a really common task for which someone has developed a quick, shell-friendly shortcut.

I tried this:

function Buffer-Object 
{
    [CmdletBinding()]
    param (
        [parameter(Mandatory=$True, ValueFromPipeline=$True)]
        [psobject] $InputObject
    )

    begin { $buf = new-list psobject }
    process { $buf.Add($InputObject) }
    end { $buf }
}
format-xml foo | buffer-object | out-file foo

It works ok in some situations. Mapped to a short alias and rolled into a common distribution like PSCX, it would be "good enough" for quick interactive tasks. Unfortunately it appears that some cmdlets (including out-file) grab the lock in their Begin{} method rather than in Process{}, so it does not solve this particular example.

Other ideas?

like image 644
Richard Berg Avatar asked Jun 23 '09 20:06

Richard Berg


1 Answers

As far as I remember (can't test now), you can read a whole file into memory with the namespace notation:

${c:file1.txt} = ${c:file1.txt} -replace "a" "o"
like image 152
guillermooo Avatar answered Dec 21 '22 19:12

guillermooo