如何根据某些条件在不同的管道中分叉数据?

时间:2017-06-14 18:38:43

标签: powershell

无论如何根据某些条件将管道数据发送到两个不同的路径,而不重新执行上游命令?这里的符号都是错的,但这是我想看到的......

PS> Get-SomeInterestingData `
    | ?{ <condition> } `
    | %{ <positive> } `
    | %{ <negative> }

我可以使用嵌套的管道/表达式吗?

PS> Get-SomeInterestingData `
    | %{ 
        $_ | ?{ <condition> } | %{ <positive> } -or `
        $_ | ?{ -not <condition> } | %{ <positive> } 
    }

如果您无法直接访问数据或数据生成功能,但是您是从管道接收的,该怎么办?比如说,作为脚本或函数param块的一部分,比如......

param(
    [Parameter(ValueFromPipeline = $true)]
    $InputObject,
)

3 个答案:

答案 0 :(得分:5)

在PowerShell 4.0及更高版本中,您可以在Where()模式下使用Split扩展名方法:

$Even,$Odd = @(1..10).Where({$_ % 2 -eq 0},'Split')

输入集合将分为2个,满足过滤条件的项目和不满足过滤条件的项目。然后,您可以处理每个,而无需再次定义输入集合

答案 1 :(得分:4)

您可以使用Switch cmdlet。

Switch(Get-SomeInterestingData){
    {<positive>} {Do Stuff}
    {<negative>} {Do Other Stuff}
}

答案 2 :(得分:2)

可悲的是,不是你希望的方式。

从技术上讲,这就是你所描述的;虽然不引人注意:

1..10 | %{
    if ($_ % 2 -eq 0) { #even pipeline
        $_ | write-host -ForegroundColor green #add whatever you want to happen on this pipeline instead of write-host 
    } else { #odd pipeline
        $_ | write-host -ForegroundColor cyan #add whatever you want to happen on this pipeline instead of write-host
    }
}

如果你想要更有趣的东西,这也会有用;虽然在许多情况下更令人困惑:

$PipelineIfTrue = {
    [CmdletBinding()]
    param ([Parameter(ValueFromPipeline = $true)][PSObject]$InputObject)
    process {
        $InputObject | write-host -ForegroundColor green
    }
}
$PipelineIfFalse = {
    [CmdletBinding()]
    param ([Parameter(ValueFromPipeline = $true)][PSObject]$InputObject)
    process {
        $InputObject | write-host -ForegroundColor cyan
    }
}

1..10 | %{$_ | &@($PipelineIfFalse, $PipelineIfTrue)[($_ % 2 -eq 0)]} 

即。创建一些采用管道输入的脚本块;一个定义如果你的条件评估为真,一个假的。

我们将它们放在数组中并使用条件的结果来索引该数组;即如果为false(index = 0),我们返回PipelineIfFalse脚本;如果为true(index = 1),我们返回PipelineIfTrue

&符号表示要执行此脚本,并且假设我们正在将当前值传递给此脚本,那么它将成为此匿名函数管道的参数。

<强>更新

因为我是一个虐待狂,所以我坚持下去。你可以这样做:

1..10 | Fork-Pipeline {$_ % 2 -eq 0} `
    { Write-Host -ForegroundColor green } `
    { Write-Host -ForegroundColor cyan }

1..10 | Fork-Pipeline `
    -If {$_ % 2 -eq 0} `
    -Then { Write-Host -ForegroundColor green } `
    -Else { Write-Host -ForegroundColor cyan }

这是Cmdlet:

function Fork-Pipeline {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true, Mandatory = $true)]
        [PSObject]$InputObject
        ,
        [Parameter(Mandatory = $true, Position=0)]
        [Alias('If')]
        [ScriptBlock]$Condition
        ,
        [Parameter(Mandatory = $true, Position=1)]
        [Alias('Then')]
        [ScriptBlock]$PiplineIfTrue
        ,
        [Parameter(Mandatory = $true, Position=2)]
        [Alias('Else')]
        [ScriptBlock]$PiplineIfFalse
    )
    begin {
        #[string]$template = '[CmdletBinding()]param([Parameter(ValueFromPipeline=$true)]$InputObject)process{{$InputObject | {0}}}'
        [string]$template = '$_ | {0}' #much simpler version of the above
        $FunctionIfTrue = [scriptblock]::Create($template -f $PiplineIfTrue.ToString())
        $FunctionIfFalse = [scriptblock]::Create($template -f $PiplineIfFalse.ToString())
    }
    process {
        if (&$Condition) {
            $InputObject | &$FunctionIfTrue
        } else {
            $InputObject | &$FunctionIfFalse
        }
    }
}

我不推荐这种做法;它不会表现得非常好,并且很可能会混淆那些习惯于处理普通PS管道的人。非常适合学术乐趣。