Powershell: Análisis / paso de parámetros: los tokens sin comillas que parecen argumentos con nombre con dos puntos como separador se dividen en dos cuando se pasan indirectamente a través de $ Args / @Args

Creado en 11 mar. 2018  ·  3Comentarios  ·  Fuente: PowerShell/PowerShell

Relacionado: # 6291, # 6292 y # 4624

Siguiendo desde https://github.com/PowerShell/PowerShell/issues/6292#issuecomment -371344550:

Nota: Los tokens en cuestión, como -foo:bar , _look_ como argumentos de PowerShell con nombre (y, detrás de escena, inicialmente siempre se analizan como tales; consulte el comentario de @BrucePay a continuación), pero deben pasarse como -es (excepto por la posibilidad de expandir la cadena) al llamar a programas externos.

Los tokens que parecen -foo.bar sufren un destino similar (ver # 6291).

Esto ya funciona como se esperaba con el paso del argumento _direct_ (por ejemplo,
echoArgs -foo:bar pasa -foo:bar como un solo argumento
), pero no al pasar $Args / salpicándolo ( @Args ).

Nota: El problema es fundamental para el uso de $Args / @Args y, aunque quizás sea menos común, también afecta su uso al llamar a comandos nativos de PowerShell; consulte el comentario a continuación .

pasos para reproducir

Ejecutar en macOS o 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

Comportamiento esperado

-foo:bar
---
-foo.bar

Comportamiento real

-foo:
bar
---
-foo
.bar

Los argumentos se parten inesperadamente en dos. Consulte el comentario vinculado para conocer los antecedentes.

Datos ambientales

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

Comentario más útil

Pasé la última semana luchando con este problema. Después de rastrearlo hasta valores de parámetro de cambio forzado (como -foo:$bar ) que no se configuran después de salpicar con @Args , pensé que esto debe ser un problema de alcance oscuro. Imagínese mi sorpresa cuando descubrí que forzar cualquier valor de parámetro de cambio de esta manera no tendría el comportamiento esperado. Lo probé incluso con la versión de Powershell 7 Preview 1 y todavía surge el mismo problema. Espero que se solucione después de más de un año de ser un problema conocido ...

Como referencia, esta es la prueba que creé para mostrar el error. Lo vi en una máquina Server 2016 con Powershell 7 Preview 1, así como en una máquina Server 2012 R2 con 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>

Todos 3 comentarios

Nota: Los tokens en cuestión, como - foo: bar, se ven como argumentos de PowerShell con nombre,

@ mklement0 Como describo en los comentarios en # 6292, estos _son_ denominados argumentos de PowerShell. Siempre. El enlace de parámetros se realiza mucho después de que se completa la compilación. Ahora, en el AST compilado, el token de -foo: tiene una bandera que indica que no había espacio después de él en el código fuente. El NativeCommandParameterBinder mira este elemento AST para ver si tiene la bandera establecida y luego concatena el parámetro y el argumento sin espacio entre ellos. Si no está configurado, se inserta un espacio. Esto solo funciona si los argumentos son literales (es decir, el NativeCommandParameter era acceso al AST para el argumento). En el caso de splatting, los argumentos son valores, no argumentos literales, por lo que se obtiene un espacio.

Una forma de solucionar esto es propagar la propiedad del token "NoSpace" en metadatos en el valor de cadena correspondiente. El NativeCommandParameterBinder podría verificar estos metadatos al convertir su matriz arg en una cadena. Probablemente valga la pena pensar en esto un poco más para ver si hay otros casos (especialmente casos específicos de * nix) que deban abordarse.

6492 (ya que se cerró como un duplicado) muestra que salpicar @args también se rompe cuando se llaman funciones de PowerShell (no solo programas externos):

Apoyar ese escenario es presumiblemente aún más complicado, porque la expectativa aquí es que los parámetros nombrados se pasen tal cual, con sus tipos originales.

Aquí hay una reproducción 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

La solución alternativa, y la solución preferible para empezar, es definir el mismo bloque param() en la función de retransmisión y splat con @PSBoundParameters .

Pasé la última semana luchando con este problema. Después de rastrearlo hasta valores de parámetro de cambio forzado (como -foo:$bar ) que no se configuran después de salpicar con @Args , pensé que esto debe ser un problema de alcance oscuro. Imagínese mi sorpresa cuando descubrí que forzar cualquier valor de parámetro de cambio de esta manera no tendría el comportamiento esperado. Lo probé incluso con la versión de Powershell 7 Preview 1 y todavía surge el mismo problema. Espero que se solucione después de más de un año de ser un problema conocido ...

Como referencia, esta es la prueba que creé para mostrar el error. Lo vi en una máquina Server 2016 con Powershell 7 Preview 1, así como en una máquina Server 2012 R2 con 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>
¿Fue útil esta página
0 / 5 - 0 calificaciones