如何在 Powershell 中使用破折号参数?

Lad*_*lin 5 powershell parameter-passing

我正在将脚本从 bash 移植到 PowerShell,并且我希望在两者中保持对参数解析的相同支持。在 bash 中,可能的参数之一是--,我还想在 PowerShell 中检测该参数。然而,到目前为止我所尝试的一切都不起作用。param($-)我无法将其定义为导致编译错误的参数。另外,如果我决定完全放弃 PowerShell 参数处理,只使用$args一切看起来不错,但当我运行该函数时,--参数会丢失。

Function Test-Function {
    Write-Host $args
}

Test-Function -- -args go -here # Prints "-args go -here"
Run Code Online (Sandbox Code Playgroud)

我也知道$PSBoundParameters,但该值不存在,因为我无法绑定名为 的参数$-。我可以尝试其他机制或解决方案吗?

有关更多背景信息,请注意我使用 PowerShell 是一个副作用。这预计不会用作普通的 PowerShell 命令,我还围绕此编写了一个批处理包装器,但包装器的逻辑比我想要批量编写的更复杂,因此批处理包装器仅调用 PowerShell 函数,然后进行更复杂的处理。

mkl*_*nt0 3

顺便说一句:PowerShell 允许使用令人惊讶的变量名称范围,但您必须将它们括起来{...}才能被识别;也就是说,${-}技术上可行,但并不能解决您的问题。

挑战在于PowerShell 会悄悄地从参数列表中删除 ---保留该标记的唯一方法是在其前面加上 PSv3+停止解析符号 ,--%然而,这从根本上改变了参数的传递方式,并且显然是一个额外的要求,这正是您想要避免的。

你最好的选择是尝试 - 次优 -解决方法:

  • 选项 A:在批处理文件包装器中,将其转换为 PowerShell保留并传递的--特殊参数;然后,PowerShell 脚本必须将该特殊参数重新转换为.--

  • 选项 B:在 PowerShell 中执行自定义参数解析:

您可以分析$MyInvocation.Line,其中包含调用脚本的原始命令行,并查找--其中是否存在。

然而,正确实现这一点并使其稳健并非易事。
这是一个相当稳健的方法:

# Don't use `param()` or `$args` - instead, do your own argument parsing:

# Extract the argument list from the invocation command line.
$argList = ($MyInvocation.Line -replace ('^.*' + [regex]::Escape($MyInvocation.InvocationName)) -split '[;|]')[0].Trim()

# Use Invoke-Expression with a Write-Output call to parse the raw argument list,
# performing evaluation and splitting it into an array:
$customArgs = if ($argList) { @(Invoke-Expression "Write-Output -- $argList") } else { @() }

# Print the resulting arguments array for verification:
$i = 0
$customArgs | % { "Arg #$((++$i)): [$_]" }
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 毫无疑问,在某些边缘情况下,参数列表可能无法正确提取,或者原始参数的重新计算会导致副作用,但对于大多数情况 - 特别是从PowerShell外部调用时 - 应该这样做。

  • 虽然在这里很有用,但Invoke-Expression通常应该避免。

如果您的脚本已命名foo.ps1并且您将其调用为./foo.ps1 -- -args go -here,您将看到以下输出:

# Don't use `param()` or `$args` - instead, do your own argument parsing:

# Extract the argument list from the invocation command line.
$argList = ($MyInvocation.Line -replace ('^.*' + [regex]::Escape($MyInvocation.InvocationName)) -split '[;|]')[0].Trim()

# Use Invoke-Expression with a Write-Output call to parse the raw argument list,
# performing evaluation and splitting it into an array:
$customArgs = if ($argList) { @(Invoke-Expression "Write-Output -- $argList") } else { @() }

# Print the resulting arguments array for verification:
$i = 0
$customArgs | % { "Arg #$((++$i)): [$_]" }
Run Code Online (Sandbox Code Playgroud)