Search code examples
windowspowershellfilterselect-string

How to define a command alias in PowerShell for filtering output?


I need to define an alias for this:
Select-String -NotMatch -Pattern "^[\t ]+\d"

so that I can use the alias instead of writing that long string each time.
After googling for 5 minutes and doing some experiments I came up with this:

filter foo {
    $_ | Select-String -NotMatch -Pattern "^[\t ]+\d"
}

So now my script looks like this:

command1 | foo
command2 | foo
command3 | foo
command4 | foo

This is apparently working as expected, but I'm concerned about the efficiency implications of doing this.
Is the foo filter acting as a transparent alias of the longer command line, or is it creating an entire new pipe or buffer or something?


Solution

  • Is the foo filter acting as a transparent alias of the longer command line, or is it creating an entire new pipe or buffer or something?

    The latter, your current implementation is invoking Select-String per pipeline input object instead of invoking it once and processing all input. If you care about performance you should change your implementation for a steppable pipeline:

    function steppablefoo {
        param([Parameter(ValueFromPipeline)] $InputObject)
    
        begin {
            $pipe = { Select-String -NotMatch -Pattern '^[\t ]+\d' }.GetSteppablePipeline()
            $pipe.Begin($PSCmdlet)
        }
        process {
            $pipe.Process($InputObject)
        }
        end {
            $pipe.End()
        }
    }
    

    You can test it for yourself with this performance comparison:

    $tests = @{
        Filter = {
            0..300kb | foo
        }
        SteppablePipeline = {
            0..300kb | steppablefoo
        }
    }
    
    $tests.GetEnumerator() | ForEach-Object {
        [pscustomobject]@{
            Test              = $_.Key
            TotalMilliseconds = (Measure-Command { & $_.Value }).TotalMilliseconds
        }
    }