Powershell'de boş birleştirme


115

Powershell'de boş birleştirme operatörü var mı?

Bu c # komutlarını powershell'de yapabilmek istiyorum:

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

Yanıtlar:


133

Powershell 7+

Powershell 7, Powershell'de yerel boş birleştirme, boş koşullu atama ve üçlü operatörler sunar.

Boş Birleştirme

$null ?? 100    # Result is 100

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

Boş Koşullu Atama

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

Üçlü operatör

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

Önceki sürümler:

Powershell Topluluk Uzantılarına gerek yok, ifadeler bir ifade olarak aşağıdaki durumlarda standart Powershell'i kullanabilirsiniz:

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

İlk C # ifadenizin yerine geçecek:

var s = myval ?? "new value";

aşağıdakilerden biri olur (tercihe bağlı olarak):

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

veya kullanabileceğiniz $ myval içeriğine bağlı olarak:

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

ve ikinci C # ifadesi benzer şekilde eşlenir:

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

olur

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

Şimdi adil olmak gerekirse, bunlar çok çabuk değil ve C # formları kadar rahat kullanılamazlar.

Ayrıca, her şeyi daha okunaklı hale getirmek için çok basit bir işleve sarmayı düşünebilirsiniz:

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

$s = Coalesce $myval "new value"

veya muhtemelen IfNull:

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

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

Gördüğünüz gibi, çok basit bir işlev size biraz sözdizimi özgürlüğü verebilir.

GÜNCELLEME: Karışımda dikkate alınması gereken fazladan bir seçenek, daha genel bir IsTrue işlevidir:

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

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

Daha sonra, Powershell'in operatörlere biraz benzeyen takma adlar beyan etme yeteneğini birleştirin, sonunda:

New-Alias "??" Coalesce

$s = ?? $myval "new value"

New-Alias "?:" IfTrue

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

Açıkçası bu herkesin zevkine uygun olmayacak, ama aradığınız şey olabilir.

Thomas'ın belirttiği gibi, C # sürümü ile yukarıdakiler arasındaki bir diğer ince fark, C # 'nın bağımsız değişkenleri kısa devre yaptırmasıdır, ancak işlevleri / diğer adları içeren Powershell sürümleri her zaman tüm bağımsız değişkenleri değerlendirecektir. Bu bir sorunsa, ififade formunu kullanın .


6
Birleştirme operatörünün tek gerçek eşdeğeri bir if ifadesi kullanmaktır; sorun, başka bir yaklaşımın kısa devre yapmak yerine tüm işlenenleri değerlendirmesidir. "?? $ myval SomeReallyExpenisveFunction ()", $ myval boş olmasa bile işlevi çağıracaktır. Betik blokları kullanarak değerlendirmeyi geciktirebilirim, ancak komut dosyası bloklarının kapanışlar OLMADIĞINI ve işlerin hantallaşmaya başladığını unutmayın.
Thomas S. Trias

Katı modda çalışmaz - fırlatır The variable '$myval' cannot be retrieved because it has not been set..
BrainSlugs83

1
@ BrainSlugs83 Katı modda gördüğünüz hata, sunulan boş birleştirme seçenekleriyle ilgili değildir. Bu sadece standarttır, Powershell önce bir değişkenin tanımlandığını kontrol eder. $myval = $nullTesti yapmadan önce ayarlarsanız , hatanın ortadan kalkması gerekir.
StephenD

1
Uyarı, powershell tuhaflığı, null her zaman karşılaştırılmalıdır (beceriksizce), ilk olarak null yerleştirilmelidir, yani, $null -ne $a şu anda düzgün bir referans bulamıyorum, ancak uzun süredir devam eden bir uygulamadır.
dudeNumber4

90

PowerShell 7 ve üzeri

PowerShell 7 birçok yeni özellik sunar ve .NET Framework'ten .NET Core'a geçiş yapar. 2020 ortalarından itibaren, .NET Core'a güvenilmesi nedeniyle PowerShell'in eski sürümlerini tamamen değiştirmedi, ancak Microsoft, Core ailesinin nihayetinde eski Framework ailesini değiştirmeyi planladığını belirtti. Bunu okuduğunuzda, PowerShell'in uyumlu bir sürümü sisteminize önceden yüklenmiş olarak gelebilir; değilse, bkz. https://github.com/powershell/powershell .

Başına belgelerine aşağıdaki operatörler dışı-box PowerShell 7.0 desteklenir:

  1. Boş birleştirme :??
  2. Boş birleştirme ataması :??=
  3. Üçlü :... ? ... : ...

Bunlar boş birleştirme için beklediğiniz gibi çalışır:

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

Üçlü bir operatör tanıtıldığından, artık bir boş birleştirme operatörü eklendiğinde gereksiz olsa da aşağıdakiler mümkündür:

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

7.0'dan itibaren, PSNullConditionalOperatorsisteğe bağlı özellik etkinleştirilirse , belgelerde ( 1 , 2 ) açıklandığı gibi aşağıdakiler de mevcuttur :

  1. Üyeler için boş koşullu üye erişimi: ?.
  2. Diziler ve diğerleri için boş koşullu üye erişimi: ?[]

Bunların birkaç uyarısı var:

  1. Bunlar deneysel olduğu için değişebilir. Siz bunu okuduğunuzda artık deneysel olarak kabul edilmeyebilirler ve uyarıların listesi değişmiş olabilir.
  2. Değişken ${}adlarında soru işaretlerine izin verildiğinden, değişkenler deneysel operatörlerden biri tarafından takip ediliyorsa, içine alınmalıdır . Özelliklerin deneysel durumdan mezun olması durumunda durumun bu olup olmayacağı belirsizdir (bkz. Sorun # 11379 ). Örneğin ${x}?.Test(), yeni operatörü kullanır, ancak adlı bir değişken üzerinde $x?.Test()çalışır .Test()$x?
  3. ?(TypeScript'ten geliyorsanız beklediğiniz gibi bir operatör yoktur . Aşağıdakiler işe yaramaz:$x.Test?()

PowerShell 6 ve öncesi

7'den önceki PowerShell sürümlerinde gerçek bir boş birleştirme operatörü veya en azından bu tür davranışları gerçekleştirebilen bir operatör vardır. Bu operatör -ne:

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

# Output:
alpha

Boş birleştirme operatöründen biraz daha çok yönlüdür çünkü boş olmayan tüm öğelerden oluşan bir dizi oluşturur:

$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 benzer şekilde çalışır, bu da boş girdileri saymak için kullanışlıdır:

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

# Result:
2

Her neyse, işte C # ??operatörünü yansıtmak için tipik bir durum :

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

açıklama

Bu açıklama, anonim bir kullanıcıdan gelen bir düzenleme önerisine dayanmaktadır. Teşekkürler, her kimsen!

İşlem sırasına bağlı olarak, bu aşağıdaki sırayla çalışır:

  1. ,Operatör değerleri dizisi test edilecek oluşturur.
  2. -neBu durumda, boş - Belirtilen değerle aynı diziden tüm öğeler dışında operatör filtreler. Sonuç, Adım 1'de oluşturulan diziyle aynı sıradaki boş olmayan değerler dizisidir.
  3. [0] filtrelenmiş dizinin ilk öğesini seçmek için kullanılır.

Bunu basitleştirmek:

  1. Tercih edilen sırada bir dizi olası değer oluşturun
  2. Diziden tüm boş değerleri hariç tut
  3. Ortaya çıkan diziden ilk öğeyi al

Uyarılar

C # 'ın boş birleştirme operatörünün aksine, ilk adım bir dizi oluşturmak olduğundan, olası her ifade değerlendirilecektir.


Sonunda cevabınızın değiştirilmiş bir versiyonunu benimkinde kullandım , çünkü birleşikteki tüm örneklerin bir istisna atmadan boş olmasına izin vermem gerekiyordu. Bunu yapmanın çok güzel yolu, beni çok şey öğrendim. :)
Johny Skovdal

Bu yöntem, kısa devreyi önler. Bunu görmek için tanımlayın function DidItRun($a) { Write-Host "It ran with $a"; return $a }ve koşun ((DidItRun $null), (DidItRun 'alpha'), 1 -ne $null)[0].
jpmc26

@ jpmc26 Evet, tasarım gereği.
Zenexer

Bir birleştirme işlevini tanımlamaya yönelik herhangi bir girişim de kısa devreyi ortadan kaldırabilir, değil mi?
Chris F Carroll

8
Ahhhh PowerShell'in operatör önceliği beni öldürüyor! Virgül operatörünün ,bu kadar yüksek bir önceliğe sahip olduğunu her zaman unutuyorum . Bunun nasıl çalıştığı konusunda kafası karışan herkes ($null, 'alpha', 1 -ne $null)[0]için aynı şey (($null, 'alpha', 1) -ne $null)[0]. Aslında daha yüksek önceliğe sahip iki "tire" operatörü -splitve -join(ve tekli tire - yani. -4Veya -'56') 'dir.
Plüton

15

Bu, sorunun ilk yarısına verilen yarım yanıttır, yani eğer isterseniz çeyrek yanıttır, ancak kullanmak istediğiniz varsayılan değerin aslında tür için varsayılan değer olması koşuluyla boş birleştirme operatörüne çok daha basit bir alternatif vardır. :

string s = myval ?? "";

Powershell'de şu şekilde yazılabilir:

([string]myval)

Veya

int d = myval ?? 0;

Powershell'e çevirir:

([int]myval)

Bunlardan birincisini, var olmayabilecek ve varsa etrafında istenmeyen boşluklar olabilecek bir xml öğesini işlerken yararlı buldum:

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

Diziye çevrim, elemanın boş olmasına karşı koruma sağlar ve herhangi bir Trim()arıza riskini önler .


([string]$null)-> """yararlı, ancak talihsiz bir yan etki" gibi görünüyor :(
user2864740


9

Powershell Topluluk Uzantıları Modülünü yüklerseniz şunları kullanabilirsiniz:

?? Invoke-NullCoalescing için takma addır.

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

?: Invoke-Ternary'nin takma adıdır.

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

Aslında bu PowerShell komutları değil. Onları pscx ile bir araya getirdiniz:?: -> Invoke-Ternary
BartekB

... gerçek kodu ve sonucu kaçırdı ..;) Get-Command -Module pscx -CommandType takma adı | nerede {$ _. İsim -match '\ ?.' } | foreach {"{0}: {1}" -f $ _. Ad, $ _. Tanım}?:: Invoke-Ternary ?? : Invoke-NullCoalescing
BartekB

Oops ... tamamen haklısınız. Çoğu zaman o modül yüklemesine sahip olduğumu bile unutuyorum.
EBGreen



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

Çoğu zaman, birleştirme kullanırken boş dizgeyi de boş olarak değerlendirmem gerektiğini görüyorum. Bunun için Zenexer'in basit boş birleştirme için birleştirme çözümünü kullanan bir işlev yazdım ve sonra sıfır veya boş denetim için Keith Hill'i kullandım ve işlevimin her ikisini de yapabilmesi için bunu bir bayrak olarak ekledim.

Bu işlevin avantajlarından biri, istisna atmadan tüm öğelerin boş (veya boş) olmasını da sağlamasıdır. Ayrıca, PowerShell'in dizi girişlerini işleme biçimi sayesinde rastgele birçok girdi değişkeni için de kullanılabilir.

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

Bu, aşağıdaki test sonuçlarını üretir:

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

Test kodu:

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

Alabileceğim en yakın şey: $Val = $MyVal |?? "Default Value"

Yukarıdakiler için boş birleştirme operatörünü şu şekilde uyguladım :

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

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

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

Koşullu Üçlü operatör bir similary şekilde uygulanabilir.

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

Ve şu şekilde kullanılır: $Val = $MyVal |?: $MyVal "Default Value"

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.