Relacionado: # 6291, # 6292 e # 4624
Acompanhamento de https://github.com/PowerShell/PowerShell/issues/6292#issuecomment -371344550:
Observação: os tokens em questão, como -foo:bar
, _parecem_ como argumentos nomeados do PowerShell (e, nos bastidores, são inicialmente sempre analisados como tal - consulte o comentário de @BrucePay abaixo), mas devem ser transmitidos como -is (exceto para possivelmente expandir a string) ao chamar programas externos.
Os tokens que se parecem com -foo.bar
sofrem um destino semelhante (ver # 6291).
Isso já funciona conforme o esperado com a passagem de argumento _direct_ (por exemplo,
echoArgs -foo:bar
passa -foo:bar
como um único argumento
), mas não ao passar $Args
/ splatting ( @Args
).
Observação: o problema é fundamental para o uso de $Args
/ @Args
e, embora talvez menos comum, também afeta seu uso ao chamar comandos nativos do PowerShell - consulte o comentário abaixo .
Execute no macOS ou 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
Os argumentos são inesperadamente quebrados em dois. Veja o comentário vinculado para o plano de fundo.
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)
Observação: os tokens em questão, como - foo: bar, parecem argumentos nomeados do PowerShell,
@ mklement0 Conforme descrevo nos comentários em # 6292, esses _são_ chamados de argumentos do PowerShell. Sempre. A vinculação de parâmetros é feita muito depois que a compilação é concluída. Agora, no AST compilado, o token para -foo:
tem um sinalizador indicando que não havia espaço após ele no código-fonte. O NativeCommandParameterBinder
olha para este elemento AST para ver se ele tem o sinalizador definido e, em seguida, concatena o parâmetro e o argumento sem espaço entre eles. Se não estiver definido, um espaço será inserido. Isso só funciona se os argumentos forem literais (ou seja, NativeCommandParameter
foi o acesso ao AST para o argumento). No caso de splatting, os argumentos são valores, não argumentos literais, portanto, você obtém um espaço.
Uma maneira de corrigir isso é propagar a propriedade do token "NoSpace" em metadados no valor da string correspondente. O NativeCommandParameterBinder
poderia então verificar esses metadados ao converter sua matriz arg em uma string. Provavelmente, vale a pena pensar um pouco mais sobre isso para ver se há outros casos (especialmente * nix casos específicos) que devem ser resolvidos.
@args
também é interrompido ao chamar funções do PowerShell (não apenas programas externos):Suportar esse cenário é presumivelmente ainda mais complicado, porque a expectativa aqui é que os parâmetros nomeados sejam passados como estão, com seus tipos originais.
Aqui está uma reprodução simplificada:
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
A solução alternativa - e solução preferível para começar - é definir o mesmo bloco param()
na função de retransmissão e splat com @PSBoundParameters
.
Passei a última semana ou mais lutando com esse problema. Depois de rastreá-lo até valores de parâmetro de troca forçada (como -foo:$bar
) não definidos após salpicar com @Args
, pensei que esse fosse um problema de escopo obscuro. Imagine minha surpresa quando descobri que forçar qualquer valor de parâmetro de switch dessa maneira não teria o comportamento esperado. Eu testei mesmo com a versão Powershell 7 Preview 1 e o mesmo problema ainda surge. Eu espero que isso seja corrigido depois de mais de um ano sendo um problema conhecido ...
Para referência, este é o teste que criei para mostrar o bug. Vi em uma máquina Server 2016 com Powershell 7 Preview 1, bem como em uma máquina Server 2012 R2 com Powershell 5.1.
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>
Comentários muito úteis
Passei a última semana ou mais lutando com esse problema. Depois de rastreá-lo até valores de parâmetro de troca forçada (como
-foo:$bar
) não definidos após salpicar com@Args
, pensei que esse fosse um problema de escopo obscuro. Imagine minha surpresa quando descobri que forçar qualquer valor de parâmetro de switch dessa maneira não teria o comportamento esperado. Eu testei mesmo com a versão Powershell 7 Preview 1 e o mesmo problema ainda surge. Eu espero que isso seja corrigido depois de mais de um ano sendo um problema conhecido ...Para referência, este é o teste que criei para mostrar o bug. Vi em uma máquina Server 2016 com Powershell 7 Preview 1, bem como em uma máquina Server 2012 R2 com Powershell 5.1.