Powershell에서 Null 병합


115

Powershell에 null 병합 연산자가 있습니까?

powershell에서 다음 C # 명령을 수행하고 싶습니다.

var s = myval ?? "new value";
var x = myval == null ? "" : otherval;

답변:


133

Powershell 7 이상

Powershell 7은 Powershell의 기본 null 병합, null 조건부 할당 및 삼항 연산자를 도입합니다.

Null 통합

$null ?? 100    # Result is 100

"Evaluated" ?? (Expensive-Operation "Not Evaluated")    # Right side here is not evaluated

Null 조건부 할당

$x = $null
$x ??= 100    # $x is now 100
$x ??= 200    # $x remains 100

삼항 연산자

$true  ? "this value returned" : "this expression not evaluated"
$false ? "this expression not evaluated" : "this value returned"

이전 버전:

Powershell Community Extensions가 필요하지 않습니다. 표준 Powershell if 문을 표현식으로 사용할 수 있습니다.

variable = if (condition) { expr1 } else { expr2 }

따라서 다음의 첫 번째 C # 표현식을 대체합니다.

var s = myval ?? "new value";

다음 중 하나가됩니다 (선호도에 따라 다름).

$s = if ($myval -eq $null) { "new value" } else { $myval }
$s = if ($myval -ne $null) { $myval } else { "new value" }

또는 $ myval에 포함 된 내용에 따라 다음을 사용할 수 있습니다.

$s = if ($myval) { $myval } else { "new value" }

두 번째 C # 표현식은 비슷한 방식으로 매핑됩니다.

var x = myval == null ? "" : otherval;

된다

$x = if ($myval -eq $null) { "" } else { $otherval }

이제 공정하게 말하면, 이것들은 매우 깔끔하지 않으며 C # 형식만큼 사용하기 편한 곳도 없습니다.

더 읽기 쉽게 만들기 위해 매우 간단한 함수로 래핑하는 것도 고려할 수 있습니다.

function Coalesce($a, $b) { if ($a -ne $null) { $a } else { $b } }

$s = Coalesce $myval "new value"

또는 가능하면 IfNull :

function IfNull($a, $b, $c) { if ($a -eq $null) { $b } else { $c } }

$s = IfNull $myval "new value" $myval
$x = IfNull $myval "" $otherval

보시다시피 매우 간단한 함수는 구문의 자유를 상당히 줄 수 있습니다.

업데이트 : 믹스에서 고려해야 할 추가 옵션은보다 일반적인 IsTrue 함수입니다.

function IfTrue($a, $b, $c) { if ($a) { $b } else { $c } }

$x = IfTrue ($myval -eq $null) "" $otherval

그런 다음 Powershell의 연산자처럼 보이는 별칭을 선언하는 기능을 결합하면 다음과 같이됩니다.

New-Alias "??" Coalesce

$s = ?? $myval "new value"

New-Alias "?:" IfTrue

$ans = ?: ($q -eq "meaning of life") 42 $otherval

분명히 이것은 모든 사람의 취향에 맞지 않을 것이지만 당신이 찾고있는 것일 수 있습니다.

Thomas가 언급했듯이 C # 버전과 위 버전의 또 다른 미묘한 차이점은 C #이 인수의 단락을 수행하지만 함수 / 별칭을 포함하는 Powershell 버전은 항상 모든 인수를 평가한다는 것입니다. 이것이 문제라면 if표현 형식을 사용하십시오 .


6
통합 연산자에 해당하는 유일한 것은 if 문을 사용하는 것입니다. 문제는 다른 접근 방식이 단락 대신 모든 피연산자를 평가한다는 것입니다. "?? $ myval SomeReallyExpenisveFunction ()"은 $ myval이 null이 아닌 경우에도 함수를 호출합니다. 스크립트 블록을 사용하여 평가를 지연시킬 수 있다고 생각하지만 스크립트 블록은 클로저가 아니며 상황이 어색해지기 시작합니다.
Thomas S. Trias 2015

엄격 모드에서는 작동하지 않습니다 The variable '$myval' cannot be retrieved because it has not been set..
BrainSlugs83

1
@ BrainSlugs83 엄격 모드에서 표시되는 오류는 제시된 null 병합 옵션과 관련이 없습니다. 변수가 먼저 정의되었는지 확인하는 것은 표준 Powershell입니다. $myval = $null테스트를 수행하기 전에 설정 하면 오류가 사라집니다.
StephenD

1
경고, powershell quirk, null은 항상 null을 먼저두고 비교해야합니다. 즉, $null -ne $a 지금은 괜찮은 참조를 찾을 수 없습니다.
dudeNumber4 21:57:19

90

PowerShell 7 이상

PowerShell 7은 많은 새로운 기능을 도입하고 .NET Framework에서 .NET Core로 마이그레이션합니다. 2020 년 중반 현재 .NET Core에 대한 의존성으로 인해 레거시 버전의 PowerShell을 완전히 대체하지는 않았지만 Microsoft는 Core 제품군이 결국 레거시 Framework 제품군을 대체 할 계획이라고 밝혔습니다. 이 문서를 읽을 때 쯤이면 호환되는 PowerShell 버전이 시스템에 미리 설치되어있을 수 있습니다. 그렇지 않은 경우 https://github.com/powershell/powershell을 참조 하십시오 .

문서 , 다음 연산자는 밖으로의 상자 PowerShell을 7.0에서 지원됩니다

  1. 널 통합 :??
  2. 널 통합 할당 :??=
  3. 삼항 :... ? ... : ...

null 병합에 대해 예상 한대로 작동합니다.

$x = $a ?? $b ?? $c ?? 'default value'
$y ??= 'default value'

삼항 연산자가 도입되었으므로 이제 다음이 가능하지만 null 병합 연산자를 추가하면 불필요합니다.

$x = $a -eq $null ? $b : $a

7.0 부터는 문서 ( 1 , 2 )에 설명 된대로 PSNullConditionalOperators선택적 기능이 활성화 된 경우 다음도 사용할 수 있습니다 .

  1. 멤버에 대한 Null 조건부 멤버 액세스 : ?.
  2. 배열 등에 대한 Null 조건부 멤버 액세스 : ?[]

여기에는 몇 가지주의 사항이 있습니다.

  1. 이는 실험적이므로 변경 될 수 있습니다. 이 글을 읽을 때까지 더 이상 실험적인 것으로 간주되지 않을 수 있으며주의 사항 목록이 변경되었을 수 있습니다.
  2. ${}변수 이름에 물음표가 허용되므로 변수는 실험 연산자 중 하나가 뒤에 오는 경우 로 묶어야 합니다. 기능이 실험 상태에서 전환되는 경우에 해당되는지 확실하지 않습니다 ( 문제 # 11379 참조 ). 예를 들어 ${x}?.Test()는 new 연산자를 사용하지만 라는 변수에서 $x?.Test()실행 Test()됩니다 $x?.
  3. ?(TypeScript에서 오는 경우 예상 할 수있는 연산자 가 없습니다 . 다음은 작동하지 않습니다.$x.Test?()

PowerShell 6 이하

7 이전의 PowerShell 버전에는 실제 Null 병합 연산자 또는 최소한 이러한 동작을 수행 할 수있는 연산자가 있습니다. 그 연산자는 -ne다음과 같습니다.

# Format:
# ($a, $b, $c -ne $null)[0]
($null, 'alpha', 1 -ne $null)[0]

# Output:
alpha

null이 아닌 모든 항목의 배열을 만들기 때문에 null 병합 연산자보다 좀 더 다재다능합니다.

$items = $null, 'alpha', 5, 0, '', @(), $null, $true, $false
$instances = $items -ne $null
[string]::Join(', ', ($instances | ForEach-Object -Process { $_.GetType() }))

# Result:
System.String, System.Int32, System.Int32, System.String, System.Object[],
System.Boolean, System.Boolean

-eq 유사하게 작동하므로 null 항목을 계산하는 데 유용합니다.

($null, 'a', $null -eq $null).Length

# Result:
2

그러나 어쨌든 다음은 C #의 ??연산자 를 미러링하는 일반적인 경우입니다 .

'Filename: {0}' -f ($filename, 'Unknown' -ne $null)[0] | Write-Output

설명

이 설명은 익명 사용자의 편집 제안을 기반으로합니다. 감사합니다, 누구든!

작업 순서에 따라 다음 순서로 작동합니다.

  1. ,연산자 값의 배열이 테스트 될 만든다.
  2. -ne이 경우, 널 - 지정된 값과 일치하는 배열에서 어떤 아이템 아웃 조작 필터. 결과는 1 단계에서 만든 배열과 동일한 순서로 null이 아닌 값의 배열입니다.
  3. [0] 필터링 된 배열의 첫 번째 요소를 선택하는 데 사용됩니다.

단순화 :

  1. 선호하는 순서로 가능한 값의 배열 만들기
  2. 배열에서 모든 null 값 제외
  3. 결과 배열에서 첫 번째 항목을 가져옵니다.

주의 사항

C #의 Null 병합 연산자와 달리 첫 번째 단계는 배열을 만드는 것이므로 가능한 모든식이 평가됩니다.


나는 예외를 던지지 않고 통합의 모든 인스턴스가 null이되도록 허용해야했기 때문에 대답의 수정 된 버전을 사용했습니다 . 그래도 아주 좋은 방법은 저를 많이 배웠습니다. :)
Johny Skovdal

이 방법은 단락을 방지합니다. 이것을 보려면 정의 function DidItRun($a) { Write-Host "It ran with $a"; return $a }하고 실행 ((DidItRun $null), (DidItRun 'alpha'), 1 -ne $null)[0]하십시오.
jpmc26

@ jpmc26 예, 그것은 의도적으로 설계된 것입니다.
Zenexer

통합 함수 를 정의하려는 시도 도 단락을 제거 할 가능성이 있습니다.
Chris F Carroll

8
Ahhhh PowerShell의 연산자 우선 순위가 나를 죽입니다! 나는 항상 쉼표 연산자 ,가 그렇게 높은 우선 순위를 가지고 있다는 것을 잊어 버립니다 . 누군가를 위해이 작품, 방법에 대한 혼란 ($null, 'alpha', 1 -ne $null)[0]과 동일합니다 (($null, 'alpha', 1) -ne $null)[0]. 사실 우선 순위가 더 높은 유일한 두 개의 "대시"연산자는 -split-join(및 단항 대시? 즉 -4또는 -'56')입니다.
명왕성

15

이것은 질문의 전반부에 대한 대답의 절반에 불과하므로 원하는 경우 1/4 대답이지만 사용하려는 기본값이 실제로 유형의 기본값 인 경우 null 병합 연산자에 대한 훨씬 더 간단한 대안이 있습니다. :

string s = myval ?? "";

Powershell에서 다음과 같이 작성할 수 있습니다.

([string]myval)

또는

int d = myval ?? 0;

Powershell로 번역 :

([int]myval)

존재하지 않을 수도 있고 존재한다면 원치 않는 공백이있을 수있는 xml 요소를 처리 할 때이 중 첫 번째가 유용하다는 것을 알았습니다.

$name = ([string]$row.td[0]).Trim()

문자열로의 캐스트는 요소가 null 인 것을 방지하고 Trim()실패 위험을 방지합니다 .


([string]$null)-> ""유사한 것 같다 "유용하지만, 불행한 부작용":(
user2864740


9

Powershell Community Extensions 모듈 을 설치하면 다음을 사용할 수 있습니다.

?? Invoke-NullCoalescing의 별칭입니다.

$s = ?? {$myval}  {"New Value"}

? : Invoke-Ternary의 별칭입니다.

$x = ?: {$myval -eq $null} {""} {$otherval}

실제로 이는 PowerShell 명령이 아닙니다. pscx :? :-> Invoke-Ternary
BartekB

... 실제 코드와 결과가 누락되었습니다 ..;) Get-Command -Module pscx -CommandType alias | 여기서 {$ _. Name -match '\ ?.' } | foreach { "{0} : {1}"-f $ _. Name, $ _. Definition}? : : Invoke-Ternary ?? : Invoke-NullCoalescing
BartekB

죄송합니다 ... 완전히 맞습니다. 나는 종종 그 모듈이 로딩된다는 것을 잊어 버립니다.
EBGreen


3
@($null,$null,"val1","val2",5) | select -First 1

2
function coalesce {
   Param ([string[]]$list)
   #$default = $list[-1]
   $coalesced = ($list -ne $null)
   $coalesced[0]
 }
 function coalesce_empty { #COALESCE for empty_strings

   Param ([string[]]$list)
   #$default = $list[-1]
   $coalesced = (($list -ne $null) -ne '')[0]
   $coalesced[0]
 }

2

병합을 사용할 때 빈 문자열을 null로 처리해야하는 경우가 종종 있습니다. 저는 이것에 대한 함수를 작성했습니다.이 함수 는 단순한 null 병합을위한 통합을 위해 Zenexer 의 솔루션을 사용한 다음 null 또는 빈 검사를 위해 Keith Hill 을 사용 하고 내 함수가 둘 다 수행 할 수 있도록 플래그로 추가했습니다.

이 함수의 장점 중 하나는 예외를 발생시키지 않고 모든 요소가 null (또는 비어 있음) 인 경우도 처리한다는 것입니다. PowerShell이 ​​배열 입력을 처리하는 방식 덕분에 임의의 많은 입력 변수에 사용할 수도 있습니다.

function Coalesce([string[]] $StringsToLookThrough, [switch]$EmptyStringAsNull) {
  if ($EmptyStringAsNull.IsPresent) {
    return ($StringsToLookThrough | Where-Object { $_ } | Select-Object -first 1)
  } else {
    return (($StringsToLookThrough -ne $null) | Select-Object -first 1)
  }  
}

이렇게하면 다음 테스트 결과가 생성됩니다.

Null coallesce tests:
1 (w/o flag)  - empty/null/'end'                 : 
1 (with flag) - empty/null/'end'                 : end
2 (w/o flag)  - empty/null                       : 
2 (with flag) - empty/null                       : 
3 (w/o flag)  - empty/null/$false/'end'          : 
3 (with flag) - empty/null/$false/'end'          : False
4 (w/o flag)  - empty/null/"$false"/'end'        : 
4 (with flag) - empty/null/"$false"/'end'        : False
5 (w/o flag)  - empty/'false'/null/"$false"/'end': 
5 (with flag) - empty/'false'/null/"$false"/'end': false

테스트 코드 :

Write-Host "Null coalesce tests:"
Write-Host "1 (w/o flag)  - empty/null/'end'                 :" (Coalesce '', $null, 'end')
Write-Host "1 (with flag) - empty/null/'end'                 :" (Coalesce '', $null, 'end' -EmptyStringAsNull)
Write-Host "2 (w/o flag)  - empty/null                       :" (Coalesce('', $null))
Write-Host "2 (with flag) - empty/null                       :" (Coalesce('', $null) -EmptyStringAsNull)
Write-Host "3 (w/o flag)  - empty/null/`$false/'end'          :" (Coalesce '', $null, $false, 'end')
Write-Host "3 (with flag) - empty/null/`$false/'end'          :" (Coalesce '', $null, $false, 'end' -EmptyStringAsNull)
Write-Host "4 (w/o flag)  - empty/null/`"`$false`"/'end'        :" (Coalesce '', $null, "$false", 'end')
Write-Host "4 (with flag) - empty/null/`"`$false`"/'end'        :" (Coalesce '', $null, "$false", 'end' -EmptyStringAsNull)
Write-Host "5 (w/o flag)  - empty/'false'/null/`"`$false`"/'end':" (Coalesce '', 'false', $null, "$false", 'end')
Write-Host "5 (with flag) - empty/'false'/null/`"`$false`"/'end':" (Coalesce '', 'false', $null, "$false", 'end' -EmptyStringAsNull)

1

내가 얻을 수있는 가장 가까운 것은 : $Val = $MyVal |?? "Default Value"

위 의 null 병합 연산자 를 다음과 같이 구현했습니다 .

function NullCoalesc {
    param (
        [Parameter(ValueFromPipeline=$true)]$Value,
        [Parameter(Position=0)]$Default
    )

    if ($Value) { $Value } else { $Default }
}

Set-Alias -Name "??" -Value NullCoalesc

조건 삼항 연산자는 similary 방식으로 구현 될 수있다.

function ConditionalTernary {
    param (
        [Parameter(ValueFromPipeline=$true)]$Value,
        [Parameter(Position=0)]$First,
        [Parameter(Position=1)]$Second
    )

    if ($Value) { $First } else { $Second }
}

Set-Alias -Name "?:" -Value ConditionalTernary

그리고 다음과 같이 사용됩니다. $Val = $MyVal |?: $MyVal "Default Value"

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