Параметр переключателя функции powershell со строковым массивом - PullRequest
2 голосов
/ 16 февраля 2020

Я изо всех сил пытаюсь понять результаты функции ниже

function testApp
{
    param(
        [string] $appName,
        [switch] $sw = $false,
        [string[]] $test,
        [string[]] $test2
    )

    Write-Host $appName - $sw - $test - $test2
}
  1. testApp -appName "TestApp" -sw $ true -test "one", "two" -test2 "three "," четыре "

Вывод: TestApp - True - один два - три четыре

testApp -appName "TestApp" -sw $ true -test "one", "two"

Вывод: TestApp - True - один два - True

Первый вывод соответствует ожидаемому. Но я не могу понять, почему второй вывод имеет «True» для массива test2, когда я не прошел его. Может ли кто-нибудь помочь мне понять причину такого поведения? Спасибо.

1 Ответ

0 голосов
/ 16 февраля 2020

Чтобы суммировать и дополнить полезные комментарии по этому вопросу Lee_Dailey , Мэтью и Маклайтон :

[switch] параметры в PowerShell (или флаги в других оболочках):

switch параметры предназначены для подразумевают $true против $false их присутствием в вызове: например, передача -sw самой сигналов $true, тогда как пропуск -sw сигналы $false.

  • Это - это возможно передать логическое значение явно , с целью передачи определенное программно значение ; Например: -sw:$var

    • Обратите внимание на обязательные : после имени переключателя, который сообщает PowerShell, что логическое значение принадлежит параметру переключателя; без этого PowerShell считает, что значение является позиционным аргументом, предназначенным для другого параметра (см. ниже).

    • Caveat : Команды могут интерпретировать -sw:$false иначе, чем пропуск -sw; ярким примером является использование общего параметра -Confirm:$false для переопределения действующего значения $ConfirmPreference.

      • Если вам нужно сделать это различие в вашем собственном коде, используйте $PSBoundParameters.ContainsKey('sw') -and -not $sw для обнаружения -sw:$false case.
  • Не назначать значение по умолчанию переменной параметра переключателя: хотя технически это возможно, соглашение предусматривает переключение по умолчанию на $false (которое в любом случае является значением [switch] экземпляра по умолчанию); то есть параметр [switch] всегда должен иметь opt-in logi c.

A [switch] переменная параметра эффективно ведет себя как Логическое значение в большинстве контекстов:

  • То есть, например, вы можете сказать if ($sw) { ... }.

  • Если вам нужен явный доступ к булевому значению в оболочке, обратитесь к свойству .IsPresent (обратите внимание, что имя свойства несколько сбивает с толку, поскольку в вызове -sw:$false переключатель все еще присутствует , но его значение , как указано в .IsPresent, равно $false).

    • Примером необходимости .IsPresent является использование Boolean как неявный индекс массива, особенно для эмуляции троичного условия [1] : ('falseValue', 'trueValue')[$sw.IsPresent]; без .IsPresent эффективное логическое значение не будет распознаваться как таковое и не будет автоматически отображаться на индекс 0$false) или 1$true).

В конечном счете, ваша проблема заключалась в том, что вы думали, что $true был аргументом для -sw, тогда как он стал позиционным аргумент неявно связан с параметром -test2 .

[switch] параметры никогда не нужно значение, поэтому следующий аргумент становится отдельным позиционным аргументом - если , вы явно указываете, что аргумент принадлежит коммутатору, следуя имени коммутатора с :, как показано выше. [2]

Позиционный против именованный передача аргумента в PowerShell:

примечание по терминологии : для концептуальной ясности термин аргумент используется для обозначения значение , переданное в объявленный параметр . Это позволяет избежать неоднозначности использования параметра ситуативно для обращения к языковой конструкции, которая получает значение против данного значения .

  • Именованный передача аргумента (привязка) относится к явному размещению целевого имени параметра перед аргументом (обычно разделяется пробелом, но в качестве альтернативы также и / или :); например, -AppName foo.

    • Порядок , в котором передаются именованные аргументы , никогда не имеет значения .
  • Позиционный (без имени) передача аргумента относится к передаче аргумента без , перед которым стоит имя его целевого параметра; например, foo.

    • Передача является позиционной в том смысле, что относительная позиция (порядок) среди других неназванных аргументов определяет, какой целевой параметр подразумевается .
  • [switch] параметры являются исключением в том смысле, что они:

    • обычно передаются только именем (-sw), подразумевая значение $true и, если передано значение , , требуется : для отделения имени от значения.
    • никогда поддержка позиционное связывание.
  • Вы можете объединить именованный проход с позиционным проходом , в этом случае именованный сначала связываются аргументы, после чего позиционные аргументы затем рассматриваются (по порядку) для привязки к еще не связанным параметрам.

  • Функции PowerShell простые функции по умолчанию. Чтобы осуществлять управление позиционным связыванием , необходимо использовать атрибуты [CmdletBinding()] и / или [Parameter()] (см. Ниже), которые неизменно превращают простую функцию в расширенную . функция .

    • Превращение простой функции в более сложную имеет большие поведенческие последствия (в основном полезные), которые подробно описаны в этом ответе .
  • По умолчанию функции PowerShell принимают позиционные аргументы для любого параметра (отличного от типа [switch]), в том порядке, в котором были объявлены параметры .

    • Кроме того, простые функции принимают произвольные дополнительные аргументы для которых не было объявлено ни одного параметра , которые собираются в переменной массива automati c $args.
  • Чтобы запретить вашей функции принимать любые позиционные аргументы по умолчанию , поместить [CmdletBinding(PositionalBinding=$false, ...)] атрибут над блоком param(...).

    • Поскольку это делает вашу функцию продвинутой , это также отключает передачу произвольной дополнительной аргументы ($args больше не применяется и не заполняется).

    • В качестве отступления: при реализации командлета (команда реализована как двоичный , обычно через C#), это поведение подразумевается .

  • К выборочно поддерживает позиционные аргументы , украшает объявления отдельных параметров атрибутом [Parameter(Position=<n>, ...)] (например, [Parameter(Position=0)] [string] $Path)

    • Примечание: Независимо от того, начинаете ли вы нумерацию с 0 или 1, это не имеет значения, если используемые числа отражают желаемый порядок среди всех позиционных параметров; 0 рекомендуется в качестве самодокументируемого соглашения, поскольку оно недвусмысленно.

    • Атрибут [Parameter(Position=<n>)] - это явное согласие, которое выборочно переопределяет [CmdletBinding(PositionalBinding=$false)]: то есть последний отключает позиционное связывание , если только явно не указано в объявлениях отдельных параметров; на самом деле, последний является подразумеваемым от первого, в этом как только вы используете один [Parameter(Position=<n>)] атрибут, вы должны использовать его для всех других параметров, которые вы хотите связать позиционно а также .


[1] Обратите внимание, что PowerShell [Core] 7.0+ изначально поддерживает троичные условия: $sw ? 'trueValue' : 'falseValue'

[2] По сути, параметры [switch] являются единственным типом, для которого PowerShell поддерживает необязательный аргумент . См. этот ответ для получения дополнительной информации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...