在不将散列或数组分配给变量的情况下进行Splatting

时间:2016-06-28 16:53:05

标签: powershell parameter-passing

我有一个返回哈希表的命令。像这样,例如:

function Get-TestArgs() { return @{a=1;b=2;c=3} }

我想将其返回值用作我的其他函数的参数:

function Test($a, $b, $c) {
    Write-Host 'A' $a
    Write-Host 'B' $b
    Write-Host 'C' $c
}

使用PowerShell的splatting功能可以实现这一点:

$testargs = @{a=1;b=2;c=3}
Test @testargs

问题是我不想将哈希值分配给中间变量。

我想到的是这些方面的东西:

Test (some splat syntax)(Get-TestArgs)

显然,这不起作用,因为它只是创建一个包含哈希的数组并传递:

Test @(Get-TestArgs)

有没有办法实现这个目标?

我关心的原因

我正在编写将手动执行的指令。这些说明将调用脚本,但在调用之间仍有一些手动干预。因此,我希望最大限度地减少命令,以减少出现问题的风险,例如变量是其他命令或输入错误。

4 个答案:

答案 0 :(得分:6)

我认为没有变量就可以使用splatting。但是,实现您正在寻找的东西的解决方法很少。

  1. 编写一个包装函数,该函数将采用哈希表并调用' real'功能。如果您想直接调用此函数,而不使用Get-TestArgs,则可以使用TestInner

    function Get-TestArgs() { return @{a=1;b=2;c=3} }
    
    function TestInner ($a, $b, $c)
    {
        write-host "a=" $a
        write-host "b=" $b
        write-host "c=" $c
    }
    
    function Test ($hash) {
        return TestInner @hash
    }
    
    Test (Get-TestArgs)
    TestInner 1 2 3
    
  2. 设计你的函数,使每个函数都将哈希表作为唯一参数 - 它是1的简化版本。它看起来有点难看 - 你无法确定Test所需的参数看着它的宣言。

    function Test ($hash)
    {
        write-host "a=" $hash.a
        write-host "b=" $hash.b
        write-host "c=" $hash.c
    }
    
    Test (Get-TestArgs)
    
  3. 使用2.中的方法,但为函数参数创建一个新类型,以便更加安全":

    add-type -TypeDefinition @"
        public class TestArg {
            public int a = 0;
            public int b = 0;
            public int c = 0;
        }
    "@
    
    function Get-TestArgs() { return new-object -type "TestArg" -Property @{a=1;b=2;c=3} }
    
    function Test ([TestArg] $o)
    {
        write-host "a=" $o.a
        write-host "b=" $o.b
        write-host "c=" $o.c
    }
    
    
    Test (Get-TestArgs) 
    
  4. 利用参数集和管道。这类似于编写包装器,但目标函数也是包装器 - 根据参数集,它将正常执行或使用splatting再次调用自身,但使用不同的参数集。

    function Test {
    param(
        [Parameter(ParameterSetName="set1",Position=0)][int]$a, 
        [Parameter(ParameterSetName="set1",Position=1)][int]$b, 
        [Parameter(ParameterSetName="set1",Position=2)][int]$c, 
        [Parameter(ParameterSetName="pipeline",ValueFromPipeLine=$true,Position=0)][Hashtable]$obj
    )
    
        if ($obj -ne $null) { return Test @obj }
    
        write-host "a=" $a
        write-host "b=" $c
        write-host "c=" $c
    
    }
    
    Test (Get-TestArgs)
    Get-TestArgs | Test        
    Test 1 2 3
    
  5. 根据您需要创建的函数数量以及打算如何调用它们,您可以选择其中一种解决方案。就个人而言,最后一个似乎是我最优雅的选择。我会选择管道:Get-TestArgs | Test在PowerShell中看起来比Test (Get-TestArgs)更自然。 例如,许多Azure PowerShell commands旨在以这种方式工作。

答案 1 :(得分:3)

我相当确定这不能用splatting完成,因为:

  

[Splatting] says, “Take whatever characters come next and assume they’re a variable name. Assume that the variable contains a hashtable, and that the keys are parameter names. Expand those out, and feed the values from the hashtable to those parameters.” That may sound like a long-winded explanation, but that’s what’s happening.

我真的认为你能做的最好的事情是:

function Test() {
    param($a, $b, $c)
    Write-Host 'A' $a
    Write-Host 'B' $b
    Write-Host 'C' $c
}

function Get-TestArgs() { @(1,2,3) }

$p = Get-TestArgs; Test @p

答案 2 :(得分:0)

我看到这篇文章的发布时间可以追溯到3年前,但是以防万一其他人(例如我)遇到这篇文章时,以下解决方案有效,并且已经在Powershell 5和3控制台(powershell.exe)中进行了测试-版本3)

使用委托并调用它:

&{ param($hashtable) &functionToRun @hashtable} (functionReturningHashTable)

基于最初发布的代码:

function Get-TestArgs() { return @{a=1;b=2;c=3} }

function Test($a, $b, $c) {
    Write-Host 'A' $a
    Write-Host 'B' $b
    Write-Host 'C' $c
}

&{ param($hashtable) &Test @hashtable} (Get-TestArgs)

返回:      A 1 B 2 C 3

您甚至可以将所需的所有命令放在最后的括号中。

假设当前目录中有3个文件a,b,c(如果未使用以下代码创建它们):

     'a','b','c' | % { New-Item -Path $_ -ItemType File }

     Mode                LastWriteTime         Length Name
     ----                -------------         ------ ----
     -a----       15/12/2019     14:34              0 a
     -a----       15/12/2019     14:34              0 b
     -a----       15/12/2019     14:34              0 c

然后您可以执行以下命令:

&{ param([hashtable]$hashtable) &Test @hashtable} (gci | group -AsHashTable -Property Name)

它返回:

     A a
     B b
     C c

使用以下代码删除创建的文件:

     'a','b','c' | % { Remove-Item -Path $_ }

此致

答案 3 :(得分:-1)

通过将哈希表通过管道传递到ForEach-Object(别名%)并使用自动变量$ PSItem(别名$ _),可以很容易地实现(而无需(用户定义)变量)。

def coins(n, m_25, m_10, m_5, m_1, m_tot, count=1):
    if m_tot == n:
        count +=1
        return count
    if m_tot > n:
        return count
    count = coins(n, m_25+1, m_10, m_5, m_1, m_tot+25, count)
    count = coins(n, m_25, m_10+1, m_5, m_1, m_tot+10, count)
    count = coins(n, m_25, m_10, m_5+1, m_1, m_tot+5, count)
    count = coins(n, m_25, m_10, m_5, m_1+1, m_tot+1, count)
    return count

def get_coins(n, m_25, m_10, m_5, m_1, m_tot):
    return coins(n, m_25, m_10, m_5, m_1, m_tot)

print(f"Coins: {get_coins(10, 2, 3, 1, 5, 2)}") 
# >> 6
都返回的

Get-TestArgs | ForEach-Object {Test @PSItem}
Get-TestArgs | % {Test @_}