Powershell: Синтаксический анализ / передача параметров: токены без кавычек, которые выглядят как именованные аргументы с двоеточием в качестве разделителя, разбиваются на две части при косвенной передаче через $ Args / @Args

Созданный на 11 мар. 2018  ·  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 , я подумал, что это, должно быть, неясная проблема с областью видимости. Каково же было мое удивление, когда я обнаружил, что принуждение любого значения параметра переключения таким образом не приведет к ожидаемому поведению. Я тестировал его даже с версией Powershell 7 Preview 1, и та же проблема все еще возникает. Я надеюсь, что это будет исправлено после более чем года существования известной проблемы ...

Для справки, это тест, который я создал, чтобы показать ошибку. Увидел это на машине Server 2016 с Powershell 7 Preview 1, а также на машине Server 2012 R2 с 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>

Все 3 Комментарий

Примечание. Рассматриваемые токены, такие как - foo: bar, выглядят как именованные аргументы PowerShell,

@ mklement0 Как я описываю в комментариях в # 6292, эти _are_ именованные аргументы PowerShell. Всегда. Привязка параметров выполняется спустя долгое время после завершения компиляции. Теперь в скомпилированном AST токен для -foo: имеет флаг, указывающий, что в исходном коде после него не было места. NativeCommandParameterBinder смотрит на этот элемент AST, чтобы увидеть, установлен ли у него флаг, затем объединяет параметр и аргумент без пробелов между ними. Если он не установлен, то вставляется пробел. Это работает, только если аргументы буквальные (т.е. NativeCommandParameter был доступом к AST для аргумента). В случае разбивки аргументы являются значениями, а не буквальными аргументами, поэтому вы получаете пробел.

Один из способов исправить это - распространить свойство токена «NoSpace» в метаданные соответствующего строкового значения. Затем NativeCommandParameterBinder может проверить эти метаданные при преобразовании массива arg в строку. Вероятно, стоит подумать об этом еще немного, чтобы увидеть, есть ли другие случаи (особенно конкретные случаи * nix), которые следует решить.

6492 (поскольку закрыто как дубликат) показывает, что отображение @args также нарушается при вызове функций PowerShell (а не только внешних программ):

Поддержка этого сценария, по-видимому, еще сложнее, потому что здесь ожидается, что именованные параметры передаются как есть, с их исходными типами.

Вот упрощенное воспроизведение:

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() в функции ретрансляции и splat с помощью @PSBoundParameters .

Я провел последнюю неделю или около того, борясь с этой проблемой. После отслеживания его до значений параметров принудительного переключения (таких как -foo:$bar ), которые не устанавливаются после разбивки с помощью @Args , я подумал, что это, должно быть, неясная проблема с областью видимости. Каково же было мое удивление, когда я обнаружил, что принуждение любого значения параметра переключения таким образом не приведет к ожидаемому поведению. Я тестировал его даже с версией Powershell 7 Preview 1, и та же проблема все еще возникает. Я надеюсь, что это будет исправлено после более чем года существования известной проблемы ...

Для справки, это тест, который я создал, чтобы показать ошибку. Увидел это на машине Server 2016 с Powershell 7 Preview 1, а также на машине Server 2012 R2 с 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>
Была ли эта страница полезной?
0 / 5 - 0 рейтинги