Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Powershell equivalent to sponge in moreutils?

Tags:

powershell

There's a GNU program called sponge that soaks up input before writing to a file so you can do something like this: cat myFile | grep "myFilter" | sponge myFile

Is there a powershell equivalent, so I can work on a file in place, without having to pipe to a temporary file?

Thanks

like image 562
nw. Avatar asked Jul 07 '11 01:07

nw.


3 Answers

In Powershell, judicious use of parentheses will force an operation to completely finish before passing data to the next command in the pipeline. The default for piping Get-Content is to pipe line by line to the next command, but with parentheses it must form a complete data set (e.g., load all lines) before continuing:

(Get-Content myFile) | Select-String 'MyFilter' | Set-Content myFile

An alternative that may use less memory (I have not benchmarked it) is to only force the results of Select-String to complete before continuing:

(Get-Content myFile | Select-String 'MyFilter') | Set-Content myFile

You could also assign things to a variable as an additional step. Any technique will load the contents into the Powershell session's memory, so be careful with big files.

Addendum: Select-String returns MatchInfo objects. Using Out-File adds pesky extra blank lines due to the way it tries to format the results as a string, but Set-Content correctly converts each object to its own string as it writes, producing better output. Being that you're coming from *nix and are used to everything returning strings (whereas Powershell returns objects), one way to force string output is to pipe them through a foreach that converts them:

(Get-Content myFile | Select-String 'MyFilter' | foreach { $_.tostring() }) | Set-Content myFile
like image 170
Joel B Fant Avatar answered Nov 04 '22 19:11

Joel B Fant


You can try this :

(Get-content myfile) | where {$_ -match "regular-expression"} | Set-content myfile

or

${full-path-file-name-of-myfile} | where {$_ -match "regular-expression"} | add-content Anotherfile

more easier to keep in mind

like image 33
JPBlanc Avatar answered Nov 04 '22 20:11

JPBlanc


two other ways come to mind - they are both the same really just one is a function the other is on the command line. (I don't know sponge on unix so I can't say for certain they mimic it).

here's the first on the command line

Get-Content .\temp.txt | 
    Select-String "grep" | 
    foreach-object -begin { [array] $out  = @()} -process { $out = $out + ($_.tostring())} -end {write-output $out}

and the second is two create a function to do it

function sponge {
    [cmdletbinding()]
    Param(
        [Parameter(
            Mandatory = $True,
            ValueFromPipeline = $True)]
        [string]$Output
    )
    Begin {
        [array] $out = @()
    }
    Process {
        $out = $out + $Output
    }
    End {
        Write-Output $Out
    }
}


Get-Content .\temp2.txt | Select-String "grep" | sponge

HTH, Matt

like image 24
Matt Avatar answered Nov 04 '22 19:11

Matt