Operador ternario en PowerShell
ternary-operator conditional-operator (11)
Aquí hay un enfoque alternativo de función personalizada:
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''
Ejemplo
1 -eq 1 |??? ''match'' : ''nomatch''
1 -eq 2 |??? ''match'' : ''nomatch''
Diferencias explicadas
-
¿Por qué son 3 signos de interrogación en lugar de 1?
-
El
?
El carácter ya es un alias paraWhere-Object
. -
??
se usa en otros idiomas como operador de fusión nula, y quería evitar confusiones.
-
El
-
¿Por qué necesitamos la tubería antes del comando?
- Como estoy utilizando la canalización para evaluar esto, todavía necesitamos este personaje para canalizar la condición en nuestra función
-
¿Qué sucede si paso en una matriz?
-
Obtenemos un resultado para cada valor;
es decir,
-2..2 |??? ''match'' : ''nomatch''
-2..2 |??? ''match'' : ''nomatch''
da:match, match, nomatch, match, match
(es decir, dado que cualquier int que no sea cero se evalúa comotrue
; mientras que cero se evalúa comofalse
). -
Si no quieres eso, convierte la matriz a bool;
([bool](-2..2)) |??? ''match'' : ''nomatch''
([bool](-2..2)) |??? ''match'' : ''nomatch''
(o simplemente:[bool](-2..2) |??? ''match'' : ''nomatch''
)
-
Obtenemos un resultado para cada valor;
es decir,
Por lo que sé, PowerShell no parece tener una expresión integrada para el llamado operador ternario .
Por ejemplo, en el lenguaje C, que admite el operador ternario, podría escribir algo como:
<condition> ? <condition-is-true> : <condition-is-false>;
Si eso realmente no existe en PowerShell, ¿cuál sería la mejor manera (es decir, fácil de leer y mantener) para lograr el mismo resultado?
Como ya lo he usado muchas veces y no lo vi listado aquí, agregaré mi pieza:
$var = @{$true="this is true";$false="this is false"}[1 -eq 1]
más feo de todos!
Dado que generalmente se usa un operador ternario al asignar un valor, debe devolver un valor. Esta es la forma en que puede funcionar:
$var=@("value if false","value if true")[[byte](condition)]
Estúpido, pero trabajando. Además, esta construcción se puede utilizar para convertir rápidamente un int en otro valor, simplemente agregue elementos de matriz y especifique una expresión que devuelva valores no negativos basados en 0.
La construcción de PowerShell más cercana que he podido inventar para emular es:
@({''condition is false''},{''condition is true''})[$condition]
PowerShell actualmente no tiene un If Inline nativo (o If ternario ) pero podría considerar usar el cmdlet personalizado:
IIf <condition> <condition-is-true> <condition-is-false>
Consulte:
PowerShell en línea si (IIf)
Powershell 7 lo tiene. https://toastit.dev/2019/09/25/ternary-operator-powershell-7/
PS C:/Users/js> 0 ? ''yes'' : ''no'' no PS C:/Users/js> 1 ? ''yes'' : ''no'' yes
Pruebe la instrucción switch de powershell como alternativa, especialmente para la asignación de variables: varias líneas, pero legible.
Ejemplo,
$WinVer = switch ( Test-Path $Env:windir/SysWOW64 ) {
$true { "64-bit" }
$false { "32-bit" }
}
"This version of Windows is $WinVer"
Recientemente he mejorado (abrir PullRequest) los operadores ternarios condicionales y de fusión nula en la lib PoweShell ''Pscx''
Por favor, busque mi solución.
Mi rama de tema de
UtilityModule_Invoke-Operators
:
UtilityModule_Invoke-Operators
Funciones:
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"
Uso
<condition_expression> |?: <true_expression> <false_expression>
<variable_expression> |?? <alternate_expression>
Como expresión puedes pasar:
$ nulo, un literal, una variable, una expresión ''externa'' ($ b -eq 4) o un bloque de script {$ b -eq 4}
Si una variable en la expresión variable es $ nulo o no existe, la expresión alternativa se evalúa como salida.
Según esta publicación de blog de PowerShell , puede crear un alias para definir un operador?:
set-alias ?: Invoke-Ternary -Option AllScope -Description "PSCX filter alias"
filter Invoke-Ternary ([scriptblock]$decider, [scriptblock]$ifTrue, [scriptblock]$ifFalse)
{
if (&$decider) {
&$ifTrue
} else {
&$ifFalse
}
}
Úselo así:
$total = ($quantity * $price ) * (?: {$quantity -le 10} {.9} {.75})
Yo también busqué una mejor respuesta, y aunque la solución en la publicación de Edward es "ok", encontré una solución mucho más natural en esta publicación de blog.
Corto y dulce:
# ---------------------------------------------------------------------------
# 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."
Lo que facilita hacer cosas como (más ejemplos en la publicación del blog):
$message == ($age > 50) ? "Old Man" :"Young Dude"
$result = If ($condition) {"true"} Else {"false"}
Todo lo demás es complejidad incidental y, por lo tanto, debe evitarse.
Para usar en o como una expresión, no solo una asignación, envuélvala en
$()
, así:
write-host $(If ($condition) {"true"} Else {"false"})