関連:#6291、#6292、および#4624
https://github.com/PowerShell/PowerShell/issues/6292#issuecomment -371344550からのフォローアップ:
注: -foo:bar
などの問題のトークンは、@BrucePayのコメントを参照してください)が、として渡される必要が
たまたま-foo.bar
ように見えるトークンも、同様の運命をたどります(#6291を参照)。
これは、_direct_引数を渡すことですでに期待どおりに機能します(例:
echoArgs -foo:bar
は-foo:bar
を単一の引数として渡します
)、ただし、 $Args
を渡す/スプラッティングする場合( @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
引数は予期せず2つに分かれています。 背景については、リンクされたコメントを参照してください。
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)
注: -foo:barなどの問題のトークンは、名前付きPowerShell引数のように見えます。
私は#6292にコメントで説明したよう@ mklement0、これら_are_は、PowerShellの引数の名前。 いつも。 パラメータのバインドは、コンパイルが完了してからかなり経ってから行われます。 コンパイルされたASTでは、 -foo:
のトークンに、ソースコードの後にスペースがないことを示すフラグがあります。 NativeCommandParameterBinder
は、このAST要素を調べて、フラグが設定されているかどうかを確認し、パラメーターと引数をスペースなしで連結します。 設定されていない場合は、スペースが挿入されます。 これは、引数がリテラルである場合にのみ機能します(つまり、 NativeCommandParameter
が引数のASTにアクセスした場合)。 スプラッティングの場合、引数は値であり、リテラル引数ではないため、スペースを取得します。
これを修正する1つの方法は、「NoSpace」トークンプロパティを対応する文字列値のメタデータに伝播することです。 NativeCommandParameterBinder
は、arg配列を文字列に変換するときに、このメタデータをチェックできます。 対処すべき他のケース(特に* nix固有のケース)があるかどうかを確認するために、これについてもう少し検討する価値があります。
@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
スプラットすることです。
私はこの1週間かそこらでこの問題に取り組んでいました。 @Args
でスプラッティングした後、強制スイッチパラメータ値( -foo:$bar
)が設定されないように追跡した後、これはあいまいなスコープの問題であるに違いないと思いました。 この方法でスイッチパラメータ値を強制しても期待どおりの動作が得られないことに気付いたときの驚きを想像してみてください。 Powershell 7 Preview 1リリースでもテストしましたが、同じ問題が発生します。 既知の問題である1年以上後にそれが修正されることを願っています...
参考までに、これはバグを示すために作成したテストです。 Powershell 7 Preview1を搭載したServer2016マシン、およびPowershell5.1を搭載したServer2012R2マシンで見ました。
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>
最も参考になるコメント
私はこの1週間かそこらでこの問題に取り組んでいました。
@Args
でスプラッティングした後、強制スイッチパラメータ値(-foo:$bar
)が設定されないように追跡した後、これはあいまいなスコープの問題であるに違いないと思いました。 この方法でスイッチパラメータ値を強制しても期待どおりの動作が得られないことに気付いたときの驚きを想像してみてください。 Powershell 7 Preview 1リリースでもテストしましたが、同じ問題が発生します。 既知の問題である1年以上後にそれが修正されることを願っています...参考までに、これはバグを示すために作成したテストです。 Powershell 7 Preview1を搭載したServer2016マシン、およびPowershell5.1を搭載したServer2012R2マシンで見ました。