Режимы синтаксического анализа PowerShell: режим аргумента (команды) или режим выражения

Может кто-нибудь объяснить, почему при возврате $ false из функции powershell вы не можете использовать оператор сравнения, чтобы определить, вернула ли функция $ false, но когда вы возвращаете $ true, сравнение оценивается как $ true?

function boolean {
    return $false
}

boolean -eq $false

function boolean {
    return $true
}

boolean -eq $true

>>>False
>>>True

Вы можете обойти это, установив вызов функции для переменной, но мне было интересно, кто-нибудь может объяснить, что здесь происходит под капотом?

function boolean {
    return $false
}

$bool = boolean 
$bool -eq $false

function boolean {
    return $true
}

$bool = boolean
$bool -eq $true

>>>True
>>>True

2 ответа

Решение

PowerShell имеет два основных режима анализа:

  • режимаргумента, который работает как традиционные оболочки

    • В режиме аргументов первый токен интерпретируется как имя команды (например, имя командлета, имя функции или имя файла исполняемого файла), за которым следует разделенный пробелами список аргументов.
  • режимвыражения, который работает как традиционные языки программирования.

Бег Get-help about_Parsingобеспечивает введение в эти режимы; короче говоря,этопервый токен, который определяет, какой режим применяется.
Также обратите внимание, что данный оператор может состоять из частей, которые анализируются в любом режиме.


boolean -eq $falseанализируется в режимеаргумента, потому что егопервый токен выглядит какимя команды(идентификатор, который может быть именем программы, именем командлета, именем функции или псевдонимом).

Следовательно,-eqа также$false интерпретируются как аргументы (значения параметров) для передачи в функциюboolean,

Так как ваш boolean функции определены таким образом, чтобы не принудительно передавать значения только объявленным параметрам, аргументы фактически игнорируются, и результатом оператора является любой вывод функции ($false или же $true).

Как продемонстрировано в ответе Майка Шепарда, вы можете заставить функцию принудительно использовать только объявленные параметры (включая ни один) с param() блок украшен [CmdletBinding()] атрибут, который по крайней мере приведет к ошибке, если вы непреднамеренно передали аргументы параметру-без boolean функция.

Вы можете обойти это, установив вызов функции для переменной

$bool = boolean   # execute function and capture result in variable
$bool -eq $false  # use variable in the comparison 

Это работает потому, что -eq заявление начинается с$ - ссылка на переменную в этом случае - которая заставляет PowerShell анализировать в режиме выражения, где -eq признается как оператор и $false как его RHS.

Тем не менее, нет необходимости в этом промежуточном этапе:

Чтобы заставить фрагмент кода интерпретироваться как выражение, заключите его в(...):

(boolean) -eq $false # Calls function 'boolean' and uses result as LHS of -eq

(...)инициирует новый контекст синтаксического анализа (который сам по себе анализируется в режиме аргумента или выражения, опять же в зависимости от 1-го токена) и обрабатывает результат как выражение. который затем позволяет использовать его как часть большего выражения, такого как операнд -eq оператор или в качестве аргумента команды.

PowerShell видит -eq как имя параметра, передаваемого в "логическую" функцию.

Чтобы увидеть это, вы можете поместить вызов функции в parens:

function boolean {
    return $false
}

(boolean) -eq $false

function boolean {
    return $true
}

(boolean) -eq $true

Или вы можете сделать это расширенной функцией, чтобы получить ошибку с отсутствующим параметром (-eq):

function boolean {
[CmdletBinding()]
Param()
    return $false
}

boolean -eq $false

function boolean {
[CmdletBinding()]
Param()
    return $true
}

boolean -eq $true
Другие вопросы по тегам