Подтвердить что ты не робот

PowerShell, встроенный If (IIf)

Как создать оператор со встроенным If (IIf, см. также: Немедленно, если или троичный, если) в PowerShell?

Если вы также считаете, что это должна быть встроенная функция PowerShell, проголосуйте за нее: https://connect.microsoft.com/PowerShell/feedback/details/1497806/iif-statement-if-shorthand

Обновление (7 октября 2019 года)

Microsoft Connect ушел в отставку, но хорошая новость заключается в том, что поддержка троичного оператора на языке PowerShell (Core), похоже, уже на подходе...

4b9b3361

Ответ 1

Вы можете использовать собственный способ PowerShells:

"The condition is " + (&{If($Condition) {"True"} Else {"False"}}) + "."

Но так как это добавляет много скобок и скобок к вашему синтаксису, вы можете рассмотреть следующий (возможно, один из самых маленьких из существующих) CmdLet:

Function IIf($If, $Right, $Wrong) {If ($If) {$Right} Else {$Wrong}}

Что упростит вашу команду:

"The condition is " + (IIf $Condition "True" "False") + "."

Добавлено 2014-09-19:

Я уже некоторое время использую командлет IIf, и я все еще думаю, что он сделает синтаксис более читабельным во многих случаях, но, как я согласен с замечанием Джейсона о нежелательном побочном эффекте, оба возможных значения будут оценены даже очевидно, используется только одно значение, я немного изменил командлет IIf:

Function IIf($If, $IfTrue, $IfFalse) {
    If ($If) {If ($IfTrue -is "ScriptBlock") {&$IfTrue} Else {$IfTrue}}
    Else {If ($IfFalse -is "ScriptBlock") {&$IfFalse} Else {$IfFalse}}
}

Теперь вы можете добавить ScriptBlock (в окружении {}) вместо объекта, который не будет оцениваться, если он не требуется, как показано в этом примере:

IIf $a {1/$a} NaN

Или встроенный:

"The multiplicative inverse of $a is $(IIf $a {1/$a} NaN)."

В случае если $a имеет значение, отличное от нуля, возвращается обратное мультипликативное значение; в противном случае он вернет NaN (где {1/$a} не оценивается).

Другой хороший пример, в котором тихий двусмысленный синтаксис будет намного проще (особенно, если вы хотите поместить его в строку), - это когда вы хотите запустить метод для объекта, который потенциально может быть $Null.

Нативный способ If сделать это будет примерно так:

If ($Object) {$a = $Object.Method()} Else {$a = $null}

(Обратите внимание, что часть Else часто требуется, например, в циклах, где вам нужно будет выполнить сброс $a.)

С командлетом IIf это будет выглядеть так:

$a = IIf $Object {$Object.Method()}

(Обратите внимание, что если $Object равен $Null, для $a автоматически будет установлено значение $Null, если значение $IfFalse не указано.)


Добавлено 2014-09-19:

Незначительное изменение в командлете IIf, который теперь устанавливает текущий объект ($_ или $PSItem):

Function IIf($If, $Then, $Else) {
    If ($If -IsNot "Boolean") {$_ = $If}
    If ($If) {If ($Then -is "ScriptBlock") {&$Then} Else {$Then}}
    Else {If ($Else -is "ScriptBlock") {&$Else} Else {$Else}}
}

Это означает, что вы можете упростить оператор (способ PowerShell) с помощью метода объекта, который потенциально может быть $Null.

Общий синтаксис этого теперь будет $a = IIf $Object {$_.Method()}. Более распространенный пример будет выглядеть примерно так:

$VolatileEnvironment = Get-Item -ErrorAction SilentlyContinue "HKCU:\Volatile Environment"
$UserName = IIf $VolatileEnvironment {$_.GetValue("UserName")}

Обратите внимание, что команда $VolatileEnvironment.GetValue("UserName") обычно приводит к "Вы не можете вызвать метод для выражения с нулевым значением." ошибка, если соответствующий реестр (HKCU:\Volatile Environment) не существует; где команда IIf $VolatileEnvironment {$_.GetValue("UserName")} просто вернет $Null.

Если параметр $If является условием (что-то вроде $Number -lt 5) или вынужденным условием (с типом [Bool]), командлет IIf не будет отменять текущий объект, например:

$RegistryKeys | ForEach {
    $UserName = IIf ($Number -lt 5) {$_.GetValue("UserName")}
}

Или:

$RegistryKeys | ForEach {
    $UserName = IIf [Bool]$VolatileEnvironment {$_.OtherMethod()}
}

Ответ 2

'The condition is {0}.' -f ('false','true')[$condition]

Ответ 3

На самом деле PowerShell возвращает значения, которые не были назначены.

$a = if ($condition) { $true } else { $false }

Пример:

"The item is $(if ($price -gt 100) { 'expensive' } else { 'cheap' })"

Давайте попробуем:

$price = 150
The item is expensive
$price = 75
The item is cheap

Ответ 4

Вот еще один способ:

$condition = $false

"The condition is $(@{$true = "true"; $false = "false"}[$condition])"

Ответ 5

Function Compare-InlineIf  
{  
[CmdletBinding()]  
    Param(  
        [Parameter(  
            position=0,  
            Mandatory=$false,  
            ValueFromPipeline=$false  
        )]  
        $Condition,  
        [Parameter(  
            position=1,  
            Mandatory=$false,  
            ValueFromPipeline=$false  
        )]  
        $IfTrue,  
        [Parameter(  
            position=2,  
            Mandatory=$false,  
            ValueFromPipeline=$false  
        )]  
        $IfFalse  
    )  
    Begin{  
        Function Usage  
        {  
            write-host @"  
Syntax  
    Compare-InlineIF [[-Condition] <test>] [[-IfTrue] <String> or <ScriptBlock>]  
 [[-IfFalse] <String> or <ScriptBlock>]  
Inputs  
    None  
    You cannot pipe objects to this cmdlet.  

Outputs  
    Depending on the evaluation of the condition statement, will be either the IfTrue or IfFalse suplied parameter values  
Examples  
   .Example 1: perform Compare-InlineIf :  
    PS C:\>Compare-InlineIf -Condition (6 -gt 5) -IfTrue "yes" -IfFalse "no"  

    yes

   .Example 2: perform IIF :  
    PS C:\>IIF (6 -gt 5) "yes" "no"  

    yes  

   .Example 3: perform IIF :  
    PS C:\>IIF '$object "'$true","'$false"  

    False  

   .Example 4: perform IIF :  
    '$object = Get-Item -ErrorAction SilentlyContinue "HKCU:\AppEvents\EventLabels\.Default\"  
    IIf '$object {'$_.GetValue("DispFilename")}  

    @mmres.dll,-5824  
"@  
        }  
    }  
    Process{  
        IF($IfTrue.count -eq 2 -and -not($IfFalse)){  
            $IfFalse = $IfTrue[1]  
            $IfTrue = $IfTrue[0]  
        }elseif($iftrue.count -ge 3 -and -not($IfFalse)){  
            Usage  
            break  
        }  
        If ($Condition -IsNot "Boolean")  
        {  
            $_ = $Condition  
        } else {}  
        If ($Condition)  
        {  
            If ($IfTrue -is "ScriptBlock")  
            {  
                &$IfTrue  
            }  
            Else  
            {  
                $IfTrue  
            }  
        }  
        Else  
        {  
            If ($IfFalse -is "ScriptBlock")  
            {  
                &$IfFalse  
            }  
            Else  
            {  
                $IfFalse  
            }  
        }  
    }  
    End{}  
}  
Set-Alias -Name IIF -Value Compare-InlineIf  

Ответ 6

Из сообщения в блоге Сделай сам: троичный оператор:

Relevant code:
# —————————————————————————
# Name:   Invoke-Ternary
# Alias:  ?:
# Author: Karl Prosser
# Desc:   Similar to the C# ? : operator e.g. 
#            _name = (value != null) ? String.Empty : value;
# Usage:  1..10 | ?: {$_ -gt 5} {'Greater than 5;$_} {'Not greater than 5';$_}
# —————————————————————————
set-alias ?: Invoke-Ternary -Option AllScope -Description 'PSCX filter alias'
filter Invoke-Ternary ([scriptblock]$decider, [scriptblock]$ifTrue, [scriptblock]$ifFalse) 
{
   if (&$decider) { 
      &$ifTrue
   } else { 
      &$ifFalse 
   }
}

И тогда вы можете использовать это так:

$total = ($quantity * $price ) * (?:  {$quantity -le 10} {.9} {.75})

Это самый близкий вариант, который я видел до сих пор.

Ответ 7

У PowerShell нет поддержки встроенных ifs. Вам нужно будет создать свою собственную функцию (как следует из другого ответа) или объединить операторы if/else в одной строке (как также предлагает другой ответ).