web-dev-qa-db-fra.com

Opérateur ternaire dans PowerShell

De ce que je sais, PowerShell ne semble pas avoir d’expression intégrée pour ce que l’on appelle l’opérateur ternary .

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, quel serait le meilleur moyen (c’est-à-dire facile à lire et à maintenir) d’atteindre le même résultat?

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

Tout le reste est une complexité accidentelle et doit donc être évité.

Pour une utilisation dans ou comme expression, pas seulement une affectation, placez-la dans $(), ainsi:

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

La construction PowerShell la plus proche que j'ai pu imaginer est la suivante:

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

Selon ce billet de blog PowerShell , 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})
24
Edward Brey

Moi aussi, je cherchais une meilleure réponse, et bien que la solution proposée dans le post d’Edward soit "ok", j’ai proposé une solution beaucoup plus naturelle dans ce 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 facilite les choses comme (plus d’exemples dans un article de blog):

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

Puisqu'un opérateur ternaire est généralement utilisé lors de l'attribution de valeur, il devrait renvoyer une valeur. Voici comment cela peut fonctionner:

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

Stupide, mais travaillant. Cette construction peut également ê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
Vesper

Essayez l'option commutateur de powershell comme alternative, en particulier pour l'affectation de variable - plusieurs lignes, mais lisible. 

Exemple,

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

Comme je l'ai déjà utilisé plusieurs fois et que je ne le vois pas dans la liste, je vais ajouter mon article:

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

le plus laid de tous!

un peu source

5
sodawillow

J'ai récemment amélioré (Open PullRequest) les opérateurs ternaires conditionnels et à coalescence nulle dans la librairie PoweShell 'Pscx'
Veuillez regarder ma solution.


Ma branche de sujet github:UtilityModule_Invoke-Operators

Les 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"

Usage

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

<variable_expression> |?? <alternate_expression>

Comme expression, vous pouvez passer:
$ null, un littéral, une variable, une expression "externe" ($ b -eq 4) ou un scriptblock {$ b -eq 4}

Si une variable dans l'expression de variable est $ null ou inexistante, l'expression alternative est évaluée en tant que sortie.

3
andiDo

PowerShell n'a actuellement pas de Inline If (ou ternary If natif, mais vous pouvez envisager d'utiliser l'applet de commande personnalisée:

IIf <condition><condition-is-true><condition-is-false>
Voir: PowerShell Inline If (IIf) } _

1
iRon

Voici une approche alternative de la fonction personnalisée:

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'

Les différences expliquées

  • Pourquoi est-ce 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 en tant qu'opérateur de coalescence nul et je voulais éviter toute confusion.
  • Pourquoi avons-nous besoin du tuyau avant la commande?
    • Puisque j'utilise le pipeline pour évaluer cela, nous avons toujours besoin de ce personnage pour canaliser la condition dans notre fonction.
  • Que se passe-t-il si je passe dans un tableau?
    • Nous obtenons un résultat pour chaque valeur; c.-à-d. -2..2 |??? 'match' : 'nomatch' donne: match, match, nomatch, match, match (c’est-à-dire que tout int différent de zéro est évalué à true; tandis que zéro correspond à false.
    • Si vous ne le souhaitez pas, convertissez le tableau en bool; ([bool](-2..2)) |??? 'match' : 'nomatch' (ou simplement: [bool](-2..2) |??? 'match' : 'nomatch')
0
JohnLBevan