据我所知,PowerShell 似乎没有所谓的 ternary operator 的内置表达式。
例如,在支持三元运算符的 C 语言中,我可以编写如下内容:
<condition> ? <condition-is-true> : <condition-is-false>;
如果这在 PowerShell 中不存在,那么实现相同结果的最佳方式(即易于阅读和维护)是什么?
$result = If ($condition) {"true"} Else {"false"}
为了在表达式中使用或用作表达式,而不仅仅是赋值,请将其包装在 $()
中,因此:
write-host $(If ($condition) {"true"} Else {"false"})
Powershell 7 有它。 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
我能想出的最接近的 PowerShell 构造是:
@({'condition is false'},{'condition is true'})[$condition]
({true}, {false})[!$condition]
稍微好一点(也许):a) 真假部分的传统顺序; b) $condition
不必只是 0 或 1 或 $false, $true。运算符 !
根据需要对其进行转换。即 $condition
可以是 42: !42 ~ $false ~ 0 ~ 第一个表达式。
{true}
和 {false}
我指的是 <true expression>
和 <false expression>
,而不是脚本块。抱歉不准确。
尝试使用 powershell 的 switch 语句作为替代方案,特别是对于变量赋值 - 多行,但可读。
例子,
$WinVer = switch ( Test-Path "$Env:windir\SysWOW64" ) {
$true { "64-bit" }
$false { "32-bit" }
}
"This version of Windows is $WinVer"
根据此 PowerShell blog post,您可以创建一个别名来定义 ?:
运算符:
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})
?:
,则需要评估参数。如果没有脚本块,它将具有类似的用法,例如。 (?: ($quantity -le 10) {.9} {.75})
我也在寻找更好的答案,虽然 Edward 帖子中的解决方案是“好的”,但我想出了一个更自然的solution in this blog post
简短而甜蜜:
# ---------------------------------------------------------------------------
# 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."
这使得做一些事情变得很容易(博客文章中的更多例子):
$message == ($age > 50) ? "Old Man" :"Young Dude"
=
作为别名,因为 ==
在 C# 和许多其他语言中用于相等检查。拥有一些 C# 经验在 powershellers 中很常见,这使得生成的代码有点混乱。 :
可能是一个更好的别名。将它与变量赋值 =:
结合使用可能会让人想起 Pascal 中使用的赋值,但在 VB.NET 或 C# 中没有任何直接等效的(我知道的)。
:
或 ~
或任何漂浮在您船上的东西。 :D set-alias : Invoke-Assignment -Option AllScope -Description "FearTheCowboy's Invoke-Assignment."
# 三元 $message =: ($age > 50) ? "Old Man" :"Young Dude"
# null 合并 $message =: $foo ?? "foo was empty"
`
从 PowerShell 版本 7 开始,三元运算符内置于 PowerShell 中。
1 -gt 2 ? "Yes" : "No"
# Returns "No"
1 -gt 2 ? 'Yes' : $null
# Get a $null response for false-y return value
$null
由于赋值时通常使用三元运算符,因此它应该返回一个值。这是可以工作的方式:
$var=@("value if false","value if true")[[byte](condition)]
愚蠢,但工作。此构造还可用于快速将 int 转换为另一个值,只需添加数组元素并指定返回基于 0 的非负值的表达式。
PowerShell 中的三元运算符是在 PowerShell version7.0 中引入的。
[Condition] ? (output if True) : (output if False)
示例 01
$a = 5; $b = 6
($a -gt $b) ? "True" : "False"
输出
False
示例 02
($a -gt $b) ? ("$a is greater than $b") : ("$a is less than $b")
输出
5 is less than 6
更多信息https://www.tutorialspoint.com/how-ternary-operator-in-powershell-works
由于我已经使用过很多次并且没有在此处列出,我将添加我的作品:
$var = @{$true="this is true";$false="this is false"}[1 -eq 1]
最丑陋的!
我最近改进了(打开 PullRequest)PoweShell lib 'Pscx' 中的三元条件和空值合并运算符,请查看我的解决方案。
我的 github 主题分支: UtilityModule_Invoke-Operators
功能:
Invoke-Ternary
Invoke-TernaryAsPipe
Invoke-NullCoalescing
NullCoalescingAsPipe
别名
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"
用法
<condition_expression> |?: <true_expression> <false_expression>
<variable_expression> |?? <alternate_expression>
作为表达式,您可以传递:$null、文字、变量、“外部”表达式 ($b -eq 4) 或脚本块 {$b -eq 4} 如果变量表达式中的变量为 $null 或不存在,替代表达式被评估为输出。
PowerShell 当前没有 没有 本机 Inline If(或 ternary If),但您可以考虑使用自定义 cmdlet :
IIf <condition> <condition-is-true> <condition-is-false>
请参阅:PowerShell inline If (IIf)
IIf
函数。但是,没有标准的 PowerShell IIf
函数/cmdlet。
如果您只是在寻找一种语法上简单的方法来分配/返回基于布尔条件的字符串或数字,您可以像这样使用乘法运算符:
"Condition is "+("true"*$condition)+("false"*!$condition)
(12.34*$condition)+(56.78*!$condition)
如果您只对结果为真时的结果感兴趣,您可以完全省略错误部分(反之亦然),例如一个简单的评分系统:
$isTall = $true
$isDark = $false
$isHandsome = $true
$score = (2*$isTall)+(4*$isDark)+(10*$isHandsome)
"Score = $score"
# or
# "Score = $((2*$isTall)+(4*$isDark)+(10*$isHandsome))"
请注意,布尔值不应是乘法中的前导项,即 $condition*"true" 等将不起作用。
这是另一种自定义函数方法:
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'
例子
1 -eq 1 |??? 'match' : 'nomatch'
1 -eq 2 |??? 'match' : 'nomatch'
差异解释
为什么是 3 个问号而不是 1 个?这 ?字符已经是 Where-Object 的别名。 ??在其他语言中用作空合并运算符,我想避免混淆。
这 ?字符已经是 Where-Object 的别名。
??在其他语言中用作空合并运算符,我想避免混淆。
为什么我们在命令之前需要管道?由于我正在使用管道来评估这个,我们仍然需要这个角色来将条件传递到我们的函数中
由于我正在使用管道来评估这个,我们仍然需要这个角色来将条件传递到我们的函数中
如果我传入一个数组会发生什么?我们得到每个值的结果;即-2..2 |??? 'match' : 'nomatch' 给出:match、match、nomatch、match、match(即因为任何非零 int 的计算结果为真;而零计算为假)。如果您不希望这样,请将数组转换为布尔值; ([bool](-2..2)) |??? 'match' : 'nomatch' (或者简单地说: [bool](-2..2) |??? 'match' : 'nomatch')
我们得到每个值的结果;即-2..2 |??? 'match' : 'nomatch' 给出:match、match、nomatch、match、match(即因为任何非零 int 的计算结果为真;而零计算为假)。
如果您不希望这样,请将数组转换为布尔值; ([bool](-2..2)) |??? 'match' : 'nomatch' (或者简单地说: [bool](-2..2) |??? 'match' : 'nomatch')
不定期副业成功案例分享
$()
包装器强制将语句评估为表达式,从而返回假值的真值,就像预期的三元运算符一样。这是您在 PowerShell AFAIK 中最接近的。