1

How do I forward all pipeline input and arguments to a command inside an alias function.

For example if I wanted to alias tail

function tail {
  coreutils tail @args
}

works fine with tail -n 5 test.txt

but not with cat test.txt | tail -n 5

even though cat test.txt | coreutils tail -n 5 works

1 Answers1

2

In the simplest case, use the following:

function tail {
  if ($MyInvocation.ExpectingInput) { # Pipeline input present.
    # $Input passes the collected pipeline input through.
    $Input | coreutils tail @args
  } else {
    coreutils tail @args
  }
}

The down-side of this approach is that all pipeline input is collected in memory first, before it is relayed to the target program.


A streaming solution - where input objects (lines) - are passed through as they become available - requires more effort:

function tail {
  [CmdletBinding(PositionalBinding=$false)]
  param(
      [Parameter(ValueFromPipeline)]
      $InputObject
      ,
      [Parameter(ValueFromRemainingArguments)]
      [string[]] $PassThruArgs
  )
  
  begin
  {
    # Set up a steppable pipeline.
    $scriptCmd = { coreutils tail $PassThruArgs }  
    $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
    $steppablePipeline.Begin($PSCmdlet)
  }
  
  process
  {
    # Pass the current pipeline input through.
    $steppablePipeline.Process($_)
  }
  
  end
  {
    $steppablePipeline.End()
  }
  
}

The above advanced function is a so-called proxy function, explained in more detail in this answer.

mklement0
  • 382,024
  • 64
  • 607
  • 775