I have two PowerShell functions, the first of which invokes the second. They both take N arguments, and one of them is defined to simply add a flag and invoke the other. Here are example definitions:
我有两个PowerShell函数,第一个调用第二个函数。它们都带有N个参数,其中一个被定义为简单地添加一个标志并调用另一个。以下是示例定义:
function inner
{
foreach( $arg in $args )
{
# do some stuff
}
}
function outer
{
inner --flag $args
}
Usage would look something like this:
用法看起来像这样:
inner foo bar baz
or this
outer wibble wobble wubble
The goal is for the latter example to be equivalent to
目标是后一个例子等同于
inner --flag wibble wobble wubble
The Problem: As defined here, the latter actually results in two arguments being passed to inner
: the first is "--flag", and the second is an array containing "wibble", "wobble", and "wubble". What I want is for inner
to receive four arguments: the flag and the three original arguments.
问题:如此处所定义,后者实际上导致两个参数传递给内部:第一个是“--flag”,第二个是包含“wibble”,“wobble”和“wubble”的数组。我想要的是内部接收四个参数:标志和三个原始参数。
So what I'm wondering is how to convince powershell to expand the $args array before passing it to inner
, passing it as N elements rather than a single array. I believe you can do this in Ruby with the splatting operator (the * character), and I'm pretty sure PowerShell can do it, but I don't recall how.
所以我想知道如何说服powershell扩展$ args数组,然后将其传递给内部,将其作为N个元素而不是单个数组传递。我相信你可以使用splatting运算符(*字符)在Ruby中执行此操作,我很确定PowerShell可以做到这一点,但我不记得如何。
4 个解决方案
#1
11
There isn't a good solution to this problem in PowerSHell V1. In V2 we added splatting (though for various reasons, we use @ instead of * for this purpose). Here's what it looks like:
PowerSHell V1中没有很好的解决方案。在V2中我们添加了splatting(虽然由于各种原因,我们使用@而不是*来实现此目的)。这是它的样子:
PS (STA-ISS) (2) > function foo ($x,$y,$z) { "x:$x y:$y z:$z" }
PS(STA-ISS)(2)> function foo($ x,$ y,$ z){“x:$ x y:$ y z:$ z”}
PS (STA-ISS) (3) > $a = 1,2,3
PS(STA-ISS)(3)> $ a = 1,2,3
PS (STA-ISS) (4) > foo $a # passed as single arg
PS(STA-ISS)(4)> foo $ a#作为单个arg传递
x:1 2 3 y: z:
x:1 2 3 y:z:
PS (STA-ISS) (5) > foo @a # splatted
PS(STA-ISS)(5)> foo @a #splatted
x:1 y:2 z:3
x:1 y:2 z:3
#2
0
Well, there may be a better way, but see if this works:
好吧,可能有更好的方法,但看看这是否有效:
inner --flag [string]::Join(" ", $args)
#3
0
Building on @EBGreen's idea, and a related question I noticed in the sidebar, a possible solution is this:
基于@ EBGreen的想法以及我在侧边栏中注意到的相关问题,可能的解决方案是:
function outer
{
invoke-expression "inner --flag $($args -join ' ')"
}
Note: This example makes use of the Powershell 2.0 CTP's new -join
operator.
注意:此示例使用Powershell 2.0 CTP的新-join运算符。
However, I'd still like to find a better method, since this feels like a hack and is horrible security-wise.
但是,我仍然希望找到一个更好的方法,因为这感觉就像一个黑客,并且在安全方面是可怕的。
#4
0
If you want a quick ready-made solution, you can copy paste mine:
如果您想要一个快速的现成解决方案,您可以复制粘贴我的:
<#
.SYNOPSIS
Asks a question and waits for user's answer
.EXAMPLE
Usage with shortcuts and without ReturnValue
Invoke-Question -Question "What would you like" -Answers "&Eggs", "&Toasts", "&Steak"
Shows the quesiton and waits for input. Let's assume user input is 'S', the return value would be 2 (index of "&Steak")
.EXAMPLE
Usage without shortcuts and with ReturnValue
Invoke-Question -Question "What would you like" -Answers "Eggs", "Toasts", "Steak" -ReturnValue
Shows the quesiton and waits for input. The answers are prefixed with numbers 1, 2 and 3 as shortcuts.
Let's assume user input is 2, the return value would be "Toasts" (prefixed numbers are "index + 1")
.EXAMPLE
Usage from pipeline with default value
@("Eggs", "Toasts", "Steak") | Invoke-Question -Question "What would you like" -ReturnValue -Default 2
Shows the quesiton and waits for input. The answers are taken from pipeline and prefixed with numbers 1, 2 and 3 as shortcuts.
Steak is marked as default. If user simply continues without a choice, Steak is chosen for her.
However, let's assume user input is 1, the return value would be "Eggs" (prefixed numbers are "index + 1")
#>
function Invoke-Question {
[CmdletBinding()]
param(
# Main question text
[Parameter(Mandatory = $true)]
[string] $Question,
# Question description, e.g. explanation or more information
[Parameter(Mandatory = $false)]
[string] $Description = "",
# Default answer as index in the array, no answer is selected by default (value -1)
[Parameter(Mandatory = $false)]
[int] $Default = -1,
# Set of answers, if the label is given with & sign, the prefixed letter is used as shortcut, e.g. "&Yes" -> Y,
# otherwise the answer is prefixed with "index + 1" number as a shortcut
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[string[]] $Answers,
# If set, returns a value of selected answer, otherwise returns its index in the Answer array
[switch] $ReturnValue
)
begin {
# init choices
$choices = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription]
$answerNumber = 1
$rememberAnswers = @()
}
process {
#init answers
foreach ($answer in $answers) {
$rememberAnswers += $answer
if ($answer -notmatch "&") {
# add number if shortcut not specified
$answer = "&$answerNumber $answer"
}
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList $answer))
$answerNumber++
}
}
end {
# ask question and return either value or index
$index = $Host.UI.PromptForChoice($Question, $Description, $choices, $Default)
if ($ReturnValue) {
$rememberAnswers[$index]
} else {
$index
}
}
}
#1
11
There isn't a good solution to this problem in PowerSHell V1. In V2 we added splatting (though for various reasons, we use @ instead of * for this purpose). Here's what it looks like:
PowerSHell V1中没有很好的解决方案。在V2中我们添加了splatting(虽然由于各种原因,我们使用@而不是*来实现此目的)。这是它的样子:
PS (STA-ISS) (2) > function foo ($x,$y,$z) { "x:$x y:$y z:$z" }
PS(STA-ISS)(2)> function foo($ x,$ y,$ z){“x:$ x y:$ y z:$ z”}
PS (STA-ISS) (3) > $a = 1,2,3
PS(STA-ISS)(3)> $ a = 1,2,3
PS (STA-ISS) (4) > foo $a # passed as single arg
PS(STA-ISS)(4)> foo $ a#作为单个arg传递
x:1 2 3 y: z:
x:1 2 3 y:z:
PS (STA-ISS) (5) > foo @a # splatted
PS(STA-ISS)(5)> foo @a #splatted
x:1 y:2 z:3
x:1 y:2 z:3
#2
0
Well, there may be a better way, but see if this works:
好吧,可能有更好的方法,但看看这是否有效:
inner --flag [string]::Join(" ", $args)
#3
0
Building on @EBGreen's idea, and a related question I noticed in the sidebar, a possible solution is this:
基于@ EBGreen的想法以及我在侧边栏中注意到的相关问题,可能的解决方案是:
function outer
{
invoke-expression "inner --flag $($args -join ' ')"
}
Note: This example makes use of the Powershell 2.0 CTP's new -join
operator.
注意:此示例使用Powershell 2.0 CTP的新-join运算符。
However, I'd still like to find a better method, since this feels like a hack and is horrible security-wise.
但是,我仍然希望找到一个更好的方法,因为这感觉就像一个黑客,并且在安全方面是可怕的。
#4
0
If you want a quick ready-made solution, you can copy paste mine:
如果您想要一个快速的现成解决方案,您可以复制粘贴我的:
<#
.SYNOPSIS
Asks a question and waits for user's answer
.EXAMPLE
Usage with shortcuts and without ReturnValue
Invoke-Question -Question "What would you like" -Answers "&Eggs", "&Toasts", "&Steak"
Shows the quesiton and waits for input. Let's assume user input is 'S', the return value would be 2 (index of "&Steak")
.EXAMPLE
Usage without shortcuts and with ReturnValue
Invoke-Question -Question "What would you like" -Answers "Eggs", "Toasts", "Steak" -ReturnValue
Shows the quesiton and waits for input. The answers are prefixed with numbers 1, 2 and 3 as shortcuts.
Let's assume user input is 2, the return value would be "Toasts" (prefixed numbers are "index + 1")
.EXAMPLE
Usage from pipeline with default value
@("Eggs", "Toasts", "Steak") | Invoke-Question -Question "What would you like" -ReturnValue -Default 2
Shows the quesiton and waits for input. The answers are taken from pipeline and prefixed with numbers 1, 2 and 3 as shortcuts.
Steak is marked as default. If user simply continues without a choice, Steak is chosen for her.
However, let's assume user input is 1, the return value would be "Eggs" (prefixed numbers are "index + 1")
#>
function Invoke-Question {
[CmdletBinding()]
param(
# Main question text
[Parameter(Mandatory = $true)]
[string] $Question,
# Question description, e.g. explanation or more information
[Parameter(Mandatory = $false)]
[string] $Description = "",
# Default answer as index in the array, no answer is selected by default (value -1)
[Parameter(Mandatory = $false)]
[int] $Default = -1,
# Set of answers, if the label is given with & sign, the prefixed letter is used as shortcut, e.g. "&Yes" -> Y,
# otherwise the answer is prefixed with "index + 1" number as a shortcut
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[string[]] $Answers,
# If set, returns a value of selected answer, otherwise returns its index in the Answer array
[switch] $ReturnValue
)
begin {
# init choices
$choices = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription]
$answerNumber = 1
$rememberAnswers = @()
}
process {
#init answers
foreach ($answer in $answers) {
$rememberAnswers += $answer
if ($answer -notmatch "&") {
# add number if shortcut not specified
$answer = "&$answerNumber $answer"
}
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList $answer))
$answerNumber++
}
}
end {
# ask question and return either value or index
$index = $Host.UI.PromptForChoice($Question, $Description, $choices, $Default)
if ($ReturnValue) {
$rememberAnswers[$index]
} else {
$index
}
}
}