Связанные: # 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)
Примечание. Рассматриваемые токены, такие как - foo: bar, выглядят как именованные аргументы PowerShell,
@ mklement0 Как я описываю в комментариях в # 6292, эти _are_ именованные аргументы PowerShell. Всегда. Привязка параметров выполняется спустя долгое время после завершения компиляции. Теперь в скомпилированном AST токен для -foo:
имеет флаг, указывающий, что в исходном коде после него не было места. NativeCommandParameterBinder
смотрит на этот элемент AST, чтобы увидеть, установлен ли у него флаг, затем объединяет параметр и аргумент без пробелов между ними. Если он не установлен, то вставляется пробел. Это работает, только если аргументы буквальные (т.е. NativeCommandParameter
был доступом к AST для аргумента). В случае разбивки аргументы являются значениями, а не буквальными аргументами, поэтому вы получаете пробел.
Один из способов исправить это - распространить свойство токена «NoSpace» в метаданные соответствующего строкового значения. Затем NativeCommandParameterBinder
может проверить эти метаданные при преобразовании массива arg в строку. Вероятно, стоит подумать об этом еще немного, чтобы увидеть, есть ли другие случаи (особенно конкретные случаи * nix), которые следует решить.
@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>
Самый полезный комментарий
Я провел последнюю неделю или около того, борясь с этой проблемой. После отслеживания его до значений параметров принудительного переключения (таких как
-foo:$bar
), которые не устанавливаются после разбивки с помощью@Args
, я подумал, что это, должно быть, неясная проблема с областью видимости. Каково же было мое удивление, когда я обнаружил, что принуждение любого значения параметра переключения таким образом не приведет к ожидаемому поведению. Я тестировал его даже с версией Powershell 7 Preview 1, и та же проблема все еще возникает. Я надеюсь, что это будет исправлено после более чем года существования известной проблемы ...Для справки, это тест, который я создал, чтобы показать ошибку. Увидел это на машине Server 2016 с Powershell 7 Preview 1, а также на машине Server 2012 R2 с Powershell 5.1.