views:

368

answers:

1

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?

+5  A: 

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"
guillermooo
Very cool! Never seen this syntax.Note that for the specific example above, you need to use parenthesis around the RHS of the assignment: ${c:foo} = ( ${c:foo} | format-xml ). Or you can use a modified pipeline: ${c:foo} | format-xml | out-file foo
Richard Berg
This is the same syntax used to access variables. There is a special interface on Providers to support this, but not all providers implement it. So that is really how you access variables in the variable provider.
JasonMArcher