PowerShell – 在动态创建的函数体内进行字符串扩展?

huangapple go评论72阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2023年6月19日 19:47:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/76506315.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定