Тернарный оператор в PowerShell
Из того, что я знаю, PowerShell, похоже, не имеет встроенного выражения для так называемого троичного оператора.
Например, на языке Си, который поддерживает троичный оператор, я мог бы написать что-то вроде:
<condition> ? <condition-is-true> : <condition-is-false>;
Если этого не существует в PowerShell, каков наилучший способ (т.е. легко читаемый и поддерживаемый) для достижения того же результата?
14 ответов
$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]
Попробуйте в качестве альтернативы оператор переключателя powershell, особенно для назначения переменных - несколько строк, но удобочитаемых.
Пример,
$WinVer = switch ( Test-Path $Env:windir\SysWOW64 ) {
$true { "64-bit" }
$false { "32-bit" }
}
"This version of Windows is $WinVer"
Согласно этому сообщению в блоге PowerShell, вы можете создать псевдоним для определения ?:
оператор:
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})
Начиная с PowerShell версии 7, тернарный оператор встроен в PowerShell.
1 -gt 2 ? "Yes" : "No"
# Returns "No"
1 -gt 2 ? 'Yes' : $null
# Get a $null response for false-y return value
Я тоже искал лучший ответ, и хотя решение в сообщении Эдварда "хорошо", в этом сообщении в блоге я нашел гораздо более естественное решение
Коротко и сладко:
# ---------------------------------------------------------------------------
# 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"
Поскольку при назначении значения обычно используется троичный оператор, он должен возвращать значение. Это способ, которым может работать:
$var=@("value if false","value if true")[[byte](condition)]
Глупо, но работает. Также эту конструкцию можно использовать для быстрого превращения типа int в другое значение, просто добавьте элементы массива и укажите выражение, которое возвращает неотрицательные значения на основе 0.
Тернарный оператор в PowerShell был представлен в PowerShell версии 7.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
Недавно я улучшил (откройте PullRequest) троичные условные операторы и операторы с нулевым слиянием в библиотеке PoweShell '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 или не существует, альтернативное выражение оценивается как выходной.
Поскольку я уже использовал это много раз и не увидел его здесь, я добавлю свою часть:
$var = @{$true="this is true";$false="this is false"}[1 -eq 1]
самый уродливый из всех!
PowerShell в настоящее время не имеет встроенного встроенного If (или троичного If), но вы можете использовать собственный командлет:
IIf <condition> <condition-is-true> <condition-is-false>
См.: PowerShell Inline If (IIf)
Если вы просто ищете синтаксически простой способ присвоить / вернуть строку или число на основе логического условия, вы можете использовать оператор умножения следующим образом:
"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
,??
используется на других языках как оператор объединения нулей, и я хотел избежать путаницы.
- Зачем нам труба перед командой?
- Поскольку я использую конвейер для оценки этого, нам все еще нужен этот символ для передачи условия в нашу функцию
- Что произойдет, если я передам массив?
- Мы получаем результат для каждого значения; т.е.
-2..2 |??? 'match' : 'nomatch'
дает:match, match, nomatch, match, match
(т. е. поскольку любое ненулевое int оценивается какtrue
; в то время как ноль оцениваетfalse
). - Если вы не хотите этого, преобразуйте массив в bool;
([bool](-2..2)) |??? 'match' : 'nomatch'
(или просто:[bool](-2..2) |??? 'match' : 'nomatch'
)
- Мы получаем результат для каждого значения; т.е.