PowerShell의 삼항 연산자


214

내가 아는 바에 따르면 PowerShell에는 소위 삼항 연산자에 대한 기본 제공식이없는 것 같습니다 .

예를 들어, 삼항 연산자를 지원하는 C 언어에서는 다음과 같이 작성할 수 있습니다.

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

이것이 PowerShell에 실제로 존재하지 않는다면 동일한 결과를 달성하는 가장 좋은 방법은 무엇입니까 (즉, 읽고 유지 관리하기 쉬운가)?


5
github.com/nightroman/PowerShellTraps/tree/master/Basic/…보십시오 . 이것이 당신이 찾고있는 것이라면 나는 그것을 대답 할 수 있습니다.
Roman Kuzmin

2
그것은의 조건 운영자 또는 삼항 경우 . "삼항 연산자"는 아닙니다. 모든 의미는 세 개의 인수를 취하는 연산자 ( 모든 연산자)이기 때문입니다.
Damien_The_Unbeliever

7
@Damien_The_Unbeliever 기술적으로는 사실이지만 종종 삼항 연산자라고합니다. 삼항 연산자 "이 연산자는 언어에서 유일하게 기존의 삼항 연산자는 종종이기 때문에, 때로는 단순히라고"조건 연산자 ""일부 언어에서는이 연산자라고합니다. ". 삼항 작동
mguassa

Visual Basic에는 실제 삼항 연산자가 없지만 IF와 IFF는 기능적으로 동등한 것으로 간주합니다.
Matt

@Matt 잘못되었습니다. 이 IIF 함수 는 항상 두 피연산자를 모두 평가합니다. If문은하지 않습니다 - 참조 stackoverflow.com/questions/1220411/...을 (새로운 VB.NET 버전은 삼항 표현 추가 If (x, y, z))
user2864740

답변:


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

그 밖의 모든 것은 부수적으로 복잡하므로 피해야합니다.

할당뿐만 아니라 표현식으로 또는 표현식으로 사용하려면 다음과 같이 묶으십시오 $().

write-host  $(If ($condition) {"true"} Else {"false"}) 

3
그것은 등호의 오른쪽에서 작동하지만 삼항 연산자를 기대하지는 않지만 "a"+ If ($ condition) { "true"} 그렇지 않으면 { "false"}"a"+ (If ($ condition) { "true"} Else { "false"}) 작동합니다 (아직 확실하지 않은 이유) : "a"+ $ (If ($ condition) { "true"} Else { "false "})
Lamarth

12
@Lamarth- $()래퍼가 명령문의 평가를 표현식으로 강제 실행하므로 삼항 연산자가 예상하는 것처럼 거짓 값의 실제 값을 리턴하므로 작동합니다. PowerShell AFAIK에서 가장 가까운 곳입니다.
KeithS

4
다른 "비 기능"몇 가지 답변과는 달리,이 것 또한 하나의 지점이 실행되어 있는지 확인합니다.
user2864740

63

에뮬레이션하기 위해 내가 찾은 가장 가까운 PowerShell 구성은 다음과 같습니다.

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

15
({true}, {false})[!$condition]약간 더 낫다 (아마도) : a) 참과 거짓 부분의 전통적인 순서; b) $condition0 또는 1 또는 $ false, $ true 일 필요는 없습니다. 연산자 !는 필요에 따라 변환합니다. 즉 $condition42 :! 42 ~ $ false ~ 0 ~ 첫 번째 표현 일 수 있습니다.
Roman Kuzmin

1
@RomanKuzmin과 동일하지 않습니다. mjolinor의 예제는 문자열을 반환합니다. 그러나 표현식에 연결된 그의 예제와 동일한 문자열 값은 스크립트 블록을 반환합니다. :-(
Michael Sorens

5
으로 {true}하고 {false}내 말은 <true expression>하고 <false expression>,하지 스크립트 블록을. 정확하지 않아 죄송합니다.
Roman Kuzmin

1
설명을 해주셔서 감사합니다. @RomanKuzmin – 현재 귀하의 제안에 가치가 있습니다.
Michael Sorens

12
이렇게하면 왼쪽 및 오른쪽 옵션을 열심히 평가해야합니다. 이는 적절한 3 진 작업과는 매우 다릅니다.
user2864740


24

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})

'결정자'가 스크립트 블록 인 이유는 없습니다. ?:평가 된 경우 인수를 평가해야합니다. 스크립트 블록이 없으면 유사한 사용법을 갖게됩니다 (예 : (?: ($quantity -le 10) {.9} {.75})
user2864740

멋진 기능이지만 스크립트를 비표준으로 렌더링 할 수 있습니다. 예를 들어 별칭 정의도 함께 포팅하지 않으면 스크립트 또는 스크립트의 일부가 포트되지 않을 수 있습니다. 이 시점에서 기본적으로 고유 한 하위 언어를 작성하고 있습니다. 이 모든 것이 복잡성 증가와 가독성 감소로 인해 유지 관리 비용이 증가 할 수 있습니다.
Vance McCorkle

1
@VanceMcCorkle 솔리드 포인트. 사용자 정의 간결함은 종종 유용하다면 그 가치가 있습니다. 그러나 상황이 거의 발생하지 않으면 "if"표현을 고수합니다.
Edward Brey

21

나도 더 나은 답변을 찾고 Edward의 게시물에있는 해결책이 "ok"인 동안이 블로그 게시물에 훨씬 더 자연스러운 해결책을 찾았 습니다.

짧고 달다:

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

1
이것은 굉장합니다. C # 및 등식 검사를 위해 다른 많은 언어에서 사용 =되기 때문에 별칭으로 사용 하는 것을 좋아하지 않습니다 ==. C #에서 약간의 경험이있는 것은 파워 쉘러에게 매우 일반적이며 결과 코드를 약간 혼란스럽게 만듭니다. :아마도 더 나은 별칭 일 것입니다. 변수 할당과 함께 사용하면 =:Pascal에서 사용 된 할당을 생각 나게 할 수 있지만 VB.NET 또는 C #에서 즉각적으로 동등한 것을 가지고 있지는 않습니다.
nohwnd

원하는 별칭으로 설정할 수 있습니다. : 또는 ~보트에 떠 다니는 것이 무엇이든. : 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"`
개럿 Serack

나는 다른 별칭을 사용하는 이유에 대해서만 언급하고있었습니다.
nohwnd

15

Powershell의 switch 문을 대안으로 사용하십시오. 특히 변수 할당-여러 줄이지 만 읽을 수 있습니다.

예,

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

1
이것은 좀 더 장황 할 수 있지만 다른 많은 답변에 비해 상당한 이점이 있습니다. 특히 외부 코드 나 스크립트 나 모듈에 복사 / 붙여 넣기 기능에 의존하지 않습니다.
bshacklett

9

삼항 연산자는 일반적으로 값을 지정할 때 사용되므로 값을 반환해야합니다. 이것이 작동하는 방법입니다.

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

멍청하지만 작동합니다. 또한이 구성을 사용하여 int를 다른 값으로 빠르게 바꿀 수 있습니다. 배열 요소를 추가하고 0부터 시작하는 음이 아닌 값을 반환하는 식을 지정하십시오.


6
이렇게하면 왼쪽 및 오른쪽 옵션을 열심히 평가해야합니다. 이는 적절한 3 진 작업과는 매우 다릅니다.
user2864740

6

이미 여러 번 사용했지만 여기에 나열되지 않았으므로 내 조각을 추가합니다.

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

가장 추한!

좀 소스


4
이렇게하면 왼쪽 및 오른쪽 옵션을 열심히 평가해야합니다. 이는 적절한 3 진 작업과는 매우 다릅니다.
user2864740

@ user2864740은 PS에 적절한 삼항 연산이 없기 때문입니다. 이것은 합성 변형입니다.
Viggo Lundén

2
적절한 삼항 연산자의 @ ViggoLundén 부족은 주석의 정확성을 감소시키지 않습니다. 이 "합성 변형" 은 다른 동작을 합니다.
user2864740

당신 말이 맞아요. 당신의 의견을 다시 읽은 후에 어떻게 그것이 실제로 차이를 만들 수 있는지 이해합니다. 감사.
sodawillow

5

최근에 PoweShell 라이브러리 'Pscx'Pls의 삼항 조건부 및 null 병합 연산자를 개선 (Open PullRequest)했습니다
. 내 솔루션을 찾습니다.


내 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이거나 존재하지 않는 경우 대체 표현식은 출력으로 평가됩니다.


4

PowerShell에는 현재 기본 인라인 If (또는 삼항 If )가 없지만 사용자 지정 cmdlet을 사용하는 것이 좋습니다.

IIf <condition> <condition-is-true> <condition-is-false>
참고 : PowerShell 인라인 If (IIf)


링크 된 포스트 쇼 방법을 만들IIf 기능을. 그러나 표준 PowerShell IIf기능 / cmdlet 은 없습니다 .
user2864740

1
@ user2864740, 그럼 무엇? 그 질문에 대한 가능한 대답으로 답을 배제 하는가? "같은 결과를 달성하는 가장 좋은 방법은 무엇입니까? 그러나 그 점을 제외하면, 링크는 이것과 매우 유사한 IIf 질문 (9 월 5 일 게시)을 나타냅니다 (중복?). 연결된 질문의 나머지 답변은 부가 가치로 볼 수도 있습니다 (그렇지 않은 경우 주로 중복되기 때문에).
iRon

약간의 설명은 먼 길 을 갔으므로 추가 정보가 추가되지 않은 경우 복제본을 닫지 않으므로 베어 링크 를 사용하지 않는 것이 좋습니다. 아주 작은 설명은 이러한 베어 링크 답변 의 품질을 크게 향상시킬 것입니다 . "Powershell은 직접 '삼항'을 지원하지 않습니다 (^하지만 다른 답변 참조). 그러나 이 방법, 또는 "..) 다른 답변을 참조하지만 그건 아니에요 추가하는 작업. 해당되는 경우 답변을 수정 / 업데이트 할 수 있습니다.
user2864740

@ user2864740, 의견을 보내 주셔서 감사합니다. 이에 따라 답변을 조정했습니다.
iRon

1

대체 사용자 정의 함수 접근 방식은 다음과 같습니다.

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'

차이점 설명

  • 왜 1이 아닌 3 개의 물음표입니까?
    • ?문자는 이미 별칭입니다 Where-Object.
    • ?? 다른 언어에서는 null 병합 연산자로 사용되며 혼란을 피하고 싶었습니다.
  • 명령 전에 파이프가 필요한 이유는 무엇입니까?
    • 파이프 라인을 사용하여이를 평가하므로 조건을 함수에 파이프하려면 여전히이 문자가 필요합니다.
  • 배열을 전달하면 어떻게됩니까?
    • 각 값에 대한 결과를 얻습니다. 즉 -2..2 |??? 'match' : 'nomatch'제공 : match, match, nomatch, match, match(예를에 0이 아닌 INT 평가하여 이후 true제로 동안 평가하여 대상을 false).
    • 원하지 않으면 배열을 부울로 변환하십시오. ([bool](-2..2)) |??? 'match' : 'nomatch'(또는 단순히 : [bool](-2..2) |??? 'match' : 'nomatch')

1

부울 조건에 따라 문자열 또는 숫자를 할당 / 반환하는 구문 적으로 간단한 방법을 찾고 있다면 다음과 같이 곱셈 연산자를 사용할 수 있습니다.

"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"등이 작동하지 않습니다.


1

PowerShell 버전 7부터는 삼항 연산자가 PowerShell에 기본 제공됩니다.

1 -gt 2 ? "Yes" : "No"
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.