wake-up-neo.com

Ternärer Operator in PowerShell

Soweit ich weiß, scheint PowerShell keinen eingebauten Ausdruck für den sogenannten ternären Operator zu haben.

In der C-Sprache, die den ternären Operator unterstützt, könnte ich beispielsweise Folgendes schreiben:

<condition> ? <condition-is-true> : <condition-is-false>;

Wenn dies in PowerShell nicht wirklich vorhanden ist, was wäre der beste Weg (d. H. Einfach zu lesen und zu warten), um dasselbe Ergebnis zu erzielen?

131
mguassa
$result = If ($condition) {"true"} Else {"false"}

Alles andere ist zufällige Komplexität und sollte daher vermieden werden.

Um in oder als Ausdruck und nicht nur als Zuweisung zu verwenden, packen Sie es in $(), also:

write-Host  $(If ($condition) {"true"} Else {"false"}) 
209
fbehrens

Das nächstgelegene PowerShell-Konstrukt, zu dem ich emulieren konnte, lautet:

@({'condition is false'},{'condition is true'})[$condition]
39
mjolinor

Mit diesem PowerShell-Blogpost können Sie einen Alias ​​erstellen, um einen ?:-Operator zu definieren:

set-alias ?: Invoke-Ternary -Option AllScope -Description "PSCX filter alias"
filter Invoke-Ternary ([scriptblock]$decider, [scriptblock]$ifTrue, [scriptblock]$ifFalse) 
{
   if (&$decider) { 
      &$ifTrue
   } else { 
      &$ifFalse 
   }
}

Verwenden Sie es so:

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

Ich suchte auch nach einer besseren Antwort, und während die Lösung in Edwards Beitrag "ok" ist, habe ich in diesem Blogbeitrag eine viel natürlichere Lösung gefunden

Kurz und bündig:

# ---------------------------------------------------------------------------
# Name:   Invoke-Assignment
# Alias:  =
# Author: Garrett Serack (@FearTheCowboy)
# Desc:   Enables expressions like the C# operators: 
#         Ternary: 
#             <condition> ? <trueresult> : <falseresult> 
#             e.g. 
#                status = (age > 50) ? "old" : "young";
#         Null-Coalescing 
#             <value> ?? <value-if-value-is-null>
#             e.g.
#                name = GetName() ?? "No Name";
#             
# Ternary Usage:  
#         $status == ($age > 50) ? "old" : "young"
#
# Null Coalescing Usage:
#         $name = (get-name) ? "No Name" 
# ---------------------------------------------------------------------------

# returns the evaluated value of the parameter passed in, 
# executing it, if it is a scriptblock   
function eval($item) {
    if( $item -ne $null ) {
        if( $item -is "ScriptBlock" ) {
            return & $item
        }
        return $item
    }
    return $null
}

# an extended assignment function; implements logic for Ternarys and Null-Coalescing expressions
function Invoke-Assignment {
    if( $args ) {
        # ternary
        if ($p = [array]::IndexOf($args,'?' )+1) {
            if (eval($args[0])) {
                return eval($args[$p])
            } 
            return eval($args[([array]::IndexOf($args,':',$p))+1]) 
        }

        # null-coalescing
        if ($p = ([array]::IndexOf($args,'??',$p)+1)) {
            if ($result = eval($args[0])) {
                return $result
            } 
            return eval($args[$p])
        } 

        # neither ternary or null-coalescing, just a value  
        return eval($args[0])
    }
    return $null
}

# alias the function to the equals sign (which doesn't impede the normal use of = )
set-alias = Invoke-Assignment -Option AllScope -Description "FearTheCowboy's Invoke-Assignment."

Das macht es einfach, Dinge zu tun wie (mehr Beispiele im Blog-Post):

$message == ($age > 50) ? "Old Man" :"Young Dude" 
19
Garrett Serack

Da bei der Zuweisung von Werten normalerweise ein ternärer Operator verwendet wird, sollte er einen Wert zurückgeben. So kann das funktionieren:

[email protected]("value if false","value if true")[[byte](condition)]

Dumm, aber funktionierte. Diese Konstruktion kann auch verwendet werden, um ein int schnell in einen anderen Wert umzuwandeln. Fügen Sie einfach Arrayelemente hinzu und geben Sie einen Ausdruck an, der 0-basierte nicht negative Werte zurückgibt.

10
Vesper

Versuchen Sie die switch - Anweisung von powershell als Alternative, insbesondere für die variable Zuweisung - mehrere Zeilen, aber lesbar. 

Beispiel,

$WinVer = switch ( Test-Path $Env:windir\SysWOW64 ) {
  $true    { "64-bit" }
  $false   { "32-bit" }
}
"This version of Windows is $WinVer"
6
nudl

Da ich dies schon viele Male verwendet habe und es hier nicht aufgeführt habe, füge ich mein Stück hinzu:

$var = @{$true="this is true";$false="this is false"}[1 -eq 1]

am hässlichsten von allen!

irgendwie Quelle

5
sodawillow

Ich habe kürzlich die ternären bedingten und nullkoaleszierenden Operatoren in der PoweShell-Bibliothek 'Pscx' verbessert (open PullRequest).
Bitte schauen Sie nach meiner Lösung.


Mein Zweig für github-Themen:UtilityModule_Invoke-Operators

Funktionen:

Invoke-Ternary
Invoke-TernaryAsPipe
Invoke-NullCoalescing
NullCoalescingAsPipe

Aliase

Set-Alias :?:   Pscx\Invoke-Ternary                     -Description "PSCX alias"
Set-Alias ?:    Pscx\Invoke-TernaryAsPipe               -Description "PSCX alias"
Set-Alias :??   Pscx\Invoke-NullCoalescing              -Description "PSCX alias"
Set-Alias ??    Pscx\Invoke-NullCoalescingAsPipe        -Description "PSCX alias"

Verwendungszweck

<condition_expression> |?: <true_expression> <false_expression>

<variable_expression> |?? <alternate_expression>

Als Ausdruck kannst du weitergeben:
$ null, ein Literal, eine Variable, ein 'externer' Ausdruck ($ b - eq 4) oder ein Skriptblock {$ b - eq 4}

Wenn eine Variable im Variablenausdruck $ null ist oder nicht vorhanden ist, wird der alternative Ausdruck als Ausgabe ausgewertet.

3
andiDo

PowerShell verfügt derzeit nicht über ein systemeigenes Inline-If (oder ternary If ). Sie könnten jedoch das benutzerdefinierte Cmdlet verwenden:

IIf <condition><condition-is-true><condition-is-false>
Siehe: PowerShell Inline If (IIf)

1
iRon

Hier ist ein alternativer Ansatz für benutzerdefinierte Funktionen:

function Test-TernaryOperatorCondition {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true, Mandatory = $true)]
        [bool]$ConditionResult
        ,
        [Parameter(Mandatory = $true, Position = 0)]
        [PSObject]$ValueIfTrue
        ,
        [Parameter(Mandatory = $true, Position = 1)]
        [ValidateSet(':')]
        [char]$Colon
        ,
        [Parameter(Mandatory = $true, Position = 2)]
        [PSObject]$ValueIfFalse
    )
    process {
        if ($ConditionResult) {
            $ValueIfTrue
        }
        else {
            $ValueIfFalse
        }
    }
}
set-alias -Name '???' -Value 'Test-TernaryOperatorCondition'

Beispiel

1 -eq 1 |??? 'match' : 'nomatch'
1 -eq 2 |??? 'match' : 'nomatch'

Unterschiede erklärt

  • Warum sind es 3 Fragezeichen anstelle von 1?
    • Das Zeichen ? ist bereits ein Alias ​​für Where-Object.
    • ?? wird in anderen Sprachen als nullkoaleszierender Operator verwendet, und ich wollte Verwirrung vermeiden.
  • Warum brauchen wir die Pipe vor dem Befehl?
    • Da ich die Pipeline dazu benutze, um dies auszuwerten, benötigen wir immer noch diesen Charakter, um die Bedingung in unsere Funktion einfließen zu lassen
  • Was passiert, wenn ich ein Array übergeben werde?
    • Wir erhalten für jeden Wert ein Ergebnis. d.h. -2..2 |??? 'match' : 'nomatch' ergibt: match, match, nomatch, match, match (d. h., da ein beliebiges Nicht-Zero int zu true ausgewertet wird, während null zu false auswertet).
    • Wenn Sie das nicht möchten, konvertieren Sie das Array in einen Bool. ([bool](-2..2)) |??? 'match' : 'nomatch' (oder einfach: [bool](-2..2) |??? 'match' : 'nomatch')
0
JohnLBevan