英文:
PowerShell - string expansion inside a dynamically created function body?
问题
我正在尝试在PowerShell中动态生成函数,这些函数的行为类似于bash中的命令别名等。
实际上,这些函数应该是从指定别名名称的字符串数组中生成的。
例如:
$commands = "build", "rebuild", "clean", "analyze"
我已经找到了如何使用New-Item -Path function: ..
来动态创建函数,但是我无法让函数体内的变量($funcname
)在其当前值上展开。相反,它总是将$funcname
添加到函数体中,然后在运行时读取变量中保留的值。
我如何强制$funcname
在函数体声明时展开为其值?
以下是示例代码:
$commands = "build", "rebuild", "clean", "analyze"
foreach($cmd in $commands)
{
$funcname="$cmd"
$body = { echo "$funcname" @args } # 在这里调用一个脚本而不是'echo'
New-Item -Path function: -Name "$funcname" -Value $body -Force
}
输出结果:
> build "test"
analyze
test
> rebuild "test"
analyze
test
...
这是函数项的内容以及它以这种方式行为的原因:
> $function:build
echo $funcname @args
英文:
I'm trying to dynamically generate functions in PowerShell that are intended to act similarly to command aliases in bash etc.
In essence the functions are supposed to be generated from a string array that specify the alias names.
e.g.:
$commands = "build", "rebuild", "clean", "analyze"
I figured out how to dynamically create functions using 'New-Item -Path function: ..
' however I'm unable to get a variable inside the function body ("$funcname") to expand to its current value. Instead it always adds $funcname to the function body which then reads the value that remains in the variable at runtime later.
How can I force $funcname to expand to its value at declaration time of the function body?
Here is the example:
$commands = "build", "rebuild", "clean", "analyze"
foreach($cmd in $commands)
{
$funcname="$cmd"
$body = { echo "$funcname" @args } # instead of 'echo' a script will be called
New-Item -Path function: -Name "$funcname" -Value $body -Force
}
Output:
> build "test"
analyze
test
> rebuild "test"
analyze
test
...
This is the function items content and the reason why it behaves that way:
> $function:build
echo $funcname @args
答案1
得分: 3
PowerShell变量是动态作用域的,这意味着变量解析会延迟到运行时 - 也就是说,当评估$funcname
时,它的值始终是最后赋给它的值(在本例中为"analyze"
)。
要解决这个问题,构建一个闭包:
$commands = "build", "rebuild", "clean", "analyze"
foreach($cmd in $commands)
{
$funcname = "$cmd"
$body = { echo "$funcname" @args }.GetNewClosure()
New-Item -Path function: -Name "$funcname" -Value $body -Force
}
GetNewClosure()
将捕获来自调用范围的$funcname
的值,并将其存储在一个动态模块中,然后将其附加到脚本块。稍后调用脚本块时,变量解析程序将使用动态模块中存储的$funcname
的副本来解析预期的值。
英文:
PowerShell variables are dynamically scoped, meaning variable resolution is deferred until runtime - meaning the value of $funcname
, when evaluated, will always be the last value assigned to it (in this case "analyze"
).
To get around this, construct a closure:
$commands = "build", "rebuild", "clean", "analyze"
foreach($cmd in $commands)
{
$funcname="$cmd"
$body = { echo "$funcname" @args }.GetNewClosure()
New-Item -Path function: -Name "$funcname" -Value $body -Force
}
GetNewClosure()
will capture the value of $funcname
from the calling scope and store it in a dynamic module which is then attached to the scriptblock. When you later invoke the script block, the variable resolution routine will run into the dynamic-module-stored copy of $funcname
and resolve the expected value.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论