Opérateur ternaire en PowerShell

D'après ce que je sais, PowerShell ne semble pas avoir d'expression intégrée pour le soi-disant opérateur ternaire .

par exemple, dans le langage C, qui supporte l'opérateur ternaire, je pourrais écrire quelque chose comme:

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

si cela n'existe pas vraiment dans PowerShell, quelle serait la meilleure façon (c.-à-d. facile à lire et à maintenir) d'accomplir le même résultat?

111
demandé sur andiDo 2015-07-10 16:26:42

10 réponses

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

tout le reste est une complexité fortuite et donc à éviter.

pour une utilisation dans ou comme une expression, pas seulement une assignation, envelopper dans $() , ainsi:

write-host  $(If ($condition) {"true"} Else {"false"}) 
181
répondu fbehrens 2017-04-06 11:33:12

la structure Powershell la plus proche que j'ai pu trouver pour imiter c'est:

. ({'condition is false'},{'condition is true'})[$condition]
30
répondu mjolinor 2015-07-10 13:52:07

Par cette PowerShell blog , vous pouvez créer un alias pour définir un ?: opérateur:

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

utilisez - le comme ceci:

$total = ($quantity * $price ) * (?:  {$quantity -le 10} {.9} {.75})
21
répondu Edward Brey 2015-11-12 13:01:29

moi aussi, j'ai cherché une meilleure réponse, et alors que la solution dans le post D'Edward est "ok", je suis venu avec un beaucoup plus naturel solution dans ce post de blog

court et doux:

# ---------------------------------------------------------------------------
# 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."

ce qui rend facile de faire des choses comme (plus d'exemples dans le blog post):

$message == ($age > 50) ? "Old Man" :"Young Dude" 
17
répondu Garrett Serack 2015-12-11 19:21:10

étant donné qu'un opérateur ternaire est habituellement utilisé pour attribuer une valeur, il doit renvoyer une valeur. C'est ainsi que cela peut fonctionner:

$var=@("value if false","value if true")[[byte](condition)]

stupide, mais travaillant. De plus, cette construction peut être utilisée pour transformer rapidement un int en une autre valeur, il suffit d'ajouter des éléments de tableau et de spécifier une expression qui renvoie des valeurs non négatives basées sur 0.

10
répondu Vesper 2015-07-10 14:16:36

comme je l'ai déjà utilisé plusieurs fois et que je ne l'ai pas vu énuméré ici, je vais ajouter mon morceau:

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

le plus laid de tous !

un peu de la source

5
répondu sodawillow 2015-09-16 18:44:22

essayez la déclaration switch de powershell comme alternative, surtout pour la cession variable-lignes multiples, mais lisible.

exemple,

$WinVer = switch ( Test-Path $Env:windir\SysWOW64 ) {
  $true    { "64-bit" }
  $false   { "32-bit" }
}
"This version of Windows is $WinVer"
3
répondu nudl 2018-01-24 20:00:37

PowerShell n'a pas actuellement un en ligne si (ou ternaire si ), mais vous pouvez envisager d'utiliser le cmdlet personnalisé:

IIf <condition> <condition-is-true> <condition-is-false>
Voir: PowerShell Inline If (IIf)
1
répondu iRon 2018-01-16 08:00:54

j'ai récemment amélioré (Open PullRequest) les opérateurs ternaires conditionnel et null-coalescing dans la PoweShell lib 'Pscx'

Pls ont un coup d'oeil pour ma solution.



ma branche thématique github: UtilityModule_Invoke-Operators



fonctions:

Invoke-Ternary
Invoke-TernaryAsPipe
Invoke-NullCoalescing
NullCoalescingAsPipe

Alias

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"

Utilisation

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

<variable_expression> |?? <alternate_expression>

comme expression vous pouvez passer:

$ null, une variable, une expression externe ($b-eq 4) ou un scriptblock {$b-eq 4}



Si une variable dans l'expression variable est $ null ou non existante, l'expression alternative est évaluée comme output.

1
répondu andiDo 2018-06-11 15:42:56

Voici une approche de fonction personnalisée alternative:

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'

exemple

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

Différences Expliquées

  • Pourquoi 3 points d'interrogation au lieu de 1?
    • le caractère ? est déjà un alias pour Where-Object .
    • ?? est utilisé dans d'autres langues comme valeur null opérateur de cogénération, et je voulais éviter toute confusion.
  • Pourquoi avons-nous besoin du tuyau avant la commande?
    • puisque j'utilise le pipeline pour évaluer ceci, nous avons encore besoin de ce caractère pour Piper la condition dans notre fonction
  • que se passe-t-il si je passe en tableau?
    • nous obtenons un résultat pour chaque valeur; i.e. -2..2 |??? 'match' : 'nomatch' donne: match, match, nomatch, match, match (i.e. depuis tout int non-zéro évalue à true ; tandis que zéro évalue à false ).
    • si vous ne voulez pas cela, convertissez le tableau en un bool; ([bool](-2..2)) |??? 'match' : 'nomatch' (ou tout simplement: [bool](-2..2) |??? 'match' : 'nomatch' )
0
répondu JohnLBevan 2017-06-13 16:58:22