Powershell: 参数解析/传递:当通过 $Args / @Args 间接传递时,看起来像带有冒号作为分隔符的命名参数的未加引号的标记被分成两部分

创建于 2018-03-11  ·  3评论  ·  资料来源: PowerShell/PowerShell

相关:#6291、#6292 和 #4624

https://github.com/PowerShell/PowerShell/issues/6292#issuecomment -371344550 跟进:

注意:有问题的令牌,例如-foo:bar ,_look_ 类似命名的 PowerShell 参数(并且,在幕后,最初总是这样解析 - 请参阅下面的@BrucePay的评论),但应该作为-is(除了可能扩展字符串)调用外部程序时。

碰巧看起来像-foo.bar遭受了类似的命运(参见 #6291)。

已经通过 _direct_ 参数传递按预期工作(例如,
echoArgs -foo:bar-foo:bar作为单个参数传递
),但不是在传递$Args / splatting ( @Args ) 时。

注意:这个问题是使用$Args / @Args ,虽然可能不太常见,但也会影响它在调用 PowerShell 原生命令时的使用 - 请参阅下面的评论

重现步骤

在 macOS 或 Linux 上运行。

function baz {
  bash -c 'for a; do echo $a; done' - $Args   # note: same with <strong i="32">@Args</strong>
}

baz -foo:bar
'---'
baz -foo.bar

预期行为

-foo:bar
---
-foo.bar

实际行为

-foo:
bar
---
-foo
.bar

争论出乎意料地一分为二。 有关背景,请参阅链接的评论。

环境数据

PowerShell Core v6.0.1 on macOS 10.13.3
PowerShell Core v6.0.1 on Ubuntu 16.04.3 LTS
PowerShell Core v6.0.1 on Microsoft Windows 10 Pro (64-bit; v10.0.15063)
Windows PowerShell v5.1.15063.674 on Microsoft Windows 10 Pro (64-bit; v10.0.15063)
Issue-Discussion WG-Language

最有用的评论

我刚刚花了一周左右的时间来解决这个问题。 在追踪到强制切换参数值(例如-foo:$bar )在与@Args splatting 后没有设置后,我认为这一定是一个模糊的范围问题。 当我发现以这种方式强制任何 switch 参数值不会有预期的行为时,想象一下我的惊讶。 即使使用 Powershell 7 Preview 1 版本,我也对其进行了测试,但仍然出现相同的问题。 我希望它会在成为已知问题一年多后得到修复......

作为参考,这是我创建的用于显示错误的测试。 在装有 Powershell 7 Preview 1 的 Server 2016 机器以及装有 Powershell 5.1 的 Server 2012 R2 机器上看到它。

function foo
{
    param(
        [switch]$testArg = $false
    )

    write-host "Test arg value: '$testArg'"
}

function bar
{
    foo <strong i="9">@Args</strong>
}

$testSplat = @{
    testArg = $false
}

write-host "#### Foo tests ####"

foo
foo -testArg:$true
foo -testArg:$false
foo <strong i="10">@testSplat</strong>

write-host "#### Bar tests ####"

bar
bar -testArg:$true
bar -testArg:$false
bar <strong i="11">@testSplat</strong>

所有3条评论

注意:有问题的标记,例如 - foo:bar看起来像命名的 PowerShell 参数,

@mklement0正如我在 #6292 的评论中所描述的,这些_are_命名为 PowerShell 参数。 总是。 参数绑定是在编译完成后很久才完成的。 现在在编译后的 AST 中, -foo:的标记有一个标志,表明源代码中它后面没有空格。 NativeCommandParameterBinder查看这个 AST 元素,看看它是否设置了标志,然后连接参数和参数,它们之间没有空格。 如果未设置,则插入一个空格。 这仅在参数是文字时才有效(即NativeCommandParameter可以访问该参数的 AST)。 在 splatting 情况下,参数是值,而不是字面参数,因此您会得到一个空格。

解决此问题的一种方法是将“NoSpace”令牌属性传播到相应字符串值的元数据中。 NativeCommandParameterBinder然后可以在将其 arg 数组转换为字符串时检查此元数据。 可能值得多考虑一下,看看是否还有其他情况(尤其是 *nix 特定情况)需要解决。

6492(因为作为重复关闭)表明在调用 PowerShell 函数(不仅仅是外部程序)时,乱码@args也被破坏:

支持这种情况可能更棘手,因为这里的期望是命名参数按原样传递,带有它们的原始类型。

这是一个简化的再现:

function b {
  Param
  (
      [Switch] $p1,
      [int] $p2,
      $rest
  )
  "`$p1: [$p1]"
  "`$p2: [$p2]"
  "`$rest: [$rest]"
}

& { b <strong i="9">@args</strong> } -p1:$false 666
$p1: [True]  # `-p1:` was interpreted as just `-p1`
$p2: [0]      # `$false`, as a separate argument, was coerced to [int] 0
$rest: [666] # what was meant to be the 2nd argument was passed as the 3rd

解决方法 - 也是首选的解决方案 - 是在中继函数中定义相同的param()块并使用@PSBoundParameters splat 。

我刚刚花了一周左右的时间来解决这个问题。 在追踪到强制切换参数值(例如-foo:$bar )在与@Args splatting 后没有设置后,我认为这一定是一个模糊的范围问题。 当我发现以这种方式强制任何 switch 参数值不会有预期的行为时,想象一下我的惊讶。 即使使用 Powershell 7 Preview 1 版本,我也对其进行了测试,但仍然出现相同的问题。 我希望它会在成为已知问题一年多后得到修复......

作为参考,这是我创建的用于显示错误的测试。 在装有 Powershell 7 Preview 1 的 Server 2016 机器以及装有 Powershell 5.1 的 Server 2012 R2 机器上看到它。

function foo
{
    param(
        [switch]$testArg = $false
    )

    write-host "Test arg value: '$testArg'"
}

function bar
{
    foo <strong i="9">@Args</strong>
}

$testSplat = @{
    testArg = $false
}

write-host "#### Foo tests ####"

foo
foo -testArg:$true
foo -testArg:$false
foo <strong i="10">@testSplat</strong>

write-host "#### Bar tests ####"

bar
bar -testArg:$true
bar -testArg:$false
bar <strong i="11">@testSplat</strong>
此页面是否有帮助?
0 / 5 - 0 等级

相关问题

andschwa picture andschwa  ·  3评论

pcgeek86 picture pcgeek86  ·  3评论

JohnLBevan picture JohnLBevan  ·  3评论

lzybkr picture lzybkr  ·  3评论

concentrateddon picture concentrateddon  ·  3评论