如何编写接受管道或文件名输入的(unix like)函数?

时间:2016-07-25 14:36:31

标签: powershell

E.g。我希望head之类的东西接受一个通过管道传输的数组然后执行select-object -first,或者接收一个文件名列表作为参数并输出每个的第一行。因此cat $filename | head应该像head $filename

一样工作

这是我迄今为止所做的尝试:

Function head( )
{
    param (
      [switch] $help = $false,
      [parameter(mandatory=$false,ValueFromPipeline=$true)] [object[]] $inputs,
      [parameter(ValueFromRemainingArguments=$true)] [String[]] $files
    )

    If( $help )
    {
        Write-Host "usage: $($MyInvocation.MYCommand) [<file>] <numLines>"
        return
    }


    $lines = 0
    if ($files -and [int]::TryParse($files[0], [ref]$lines)) {
      $null,$files = $files
    } else {
      $lines = 10
    }

    $input | select-object -First $lines
    if ($files) {get-content -TotalCount $lines $files}
}

但这导致函数忽略第一个参数:

C:\Users\idror.TLV-WPVAJ> head C:\temp\now.ps1
C:\Users\idror.TLV-WPVAJ> head C:\temp\now.ps1 C:\temp\now.ps1
Function head( )
{
    param (
          [switch] $help = $false,
          [parameter(mandatory=$false,ValueFromPipeline=$true)] [object[]] $input,
          [parameter(ValueFromRemainingArguments=$true)] [String[]] $files
        )

        If( $help )
        {
C:\Users\idror.TLV-WPVAJ> $a | head
1
2
3
C:\Users\idror.TLV-WPVAJ> $a | head 1
head : The input object cannot be bound to any parameters for the command either because the command does not take
pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
At line:1 char:6
+ $a | head 1
+      ~~~~~~
    + CategoryInfo          : InvalidArgument: (1:Int32) [head], ParameterBindingException
    + FullyQualifiedErrorId : InputObjectNotBound,head

1 个答案:

答案 0 :(得分:0)

您可以使用Parameter Sets

实现此目的
function head {
[CmdletBinding()]
param(
    [Parameter(
        ParameterSetName = 'Content',
        ValueFromPipeline = $true,
        Mandatory = $true
    )]
    [String[]]
    $Content ,

    [Parameter(
        ParameterSetName = 'File',
        ValueFromRemainingArguments = $true ,
        Mandatory = $true
    )]
    [String[]]
    $Path,

    [Parameter()]
    [uint64]
    $Count = 5
)

    Begin {
        Write-Verbose "Parameter Set Name: $($PSCmdlet.ParameterSetName)"
    }

    Process {
        Write-Verbose "Content: $Content"
        Write-Verbose "Path: $Path"
        Write-Verbose "Count: $Count"
    }
}

首先,通过运行Get-Help head

来查看此输出的帮助输出
NAME
    head

SYNTAX
   head -Content <string[]> [-Count <uint64>]  [<CommonParameters>]

   head -Path <string[]> [-Count <uint64>]  [<CommonParameters>]

您可以看到它解释了两个不同的集合,并且每个参数在其自己的集合中都是必需的。

您也可以使用-Verbose进行调用,以了解其工作原理:

# Content by pipeline
'one','two','three' | head -Verbose

# Files as an array
head -Verbose 'file1','file2','file3'

# Files as remaining arguments
head -Verbose 'file1' 'file2' 'file3'