Share via


$null hakkında bilmek istediğiniz her şey

PowerShell $null genellikle basit gibi görünür, ancak çok fazla nüansları vardır. Şimdi bir değerle $null beklenmedik bir şekilde karşılaştığınızda neler olduğunu öğrenmek için yakından bakalım$null.

Not

Bu makalenin özgün sürümü, @KevinMarquette tarafından yazılan blogda yer almıştır. PowerShell ekibi, bu içeriği bizimle paylaştığı için Kevin'e teşekkür ederiz. Lütfen PowerShellExplained.com'daki blogunu inceleyin.

NULL nedir?

NULL değerini bilinmeyen veya boş bir değer olarak düşünebilirsiniz. Bir değer veya nesne atayana kadar değişken NULL olur. Değer gerektiren ve değer NULL olduğunda hata oluşturan bazı komutlar olduğundan bu önemli olabilir.

PowerShell $null

$null , PowerShell'de NULL değerini temsil etmek için kullanılan otomatik bir değişkendir. Bunu değişkenlere atayabilir, karşılaştırmalarda kullanabilir ve bir koleksiyonda NULL için yer tutucu olarak kullanabilirsiniz.

PowerShell, NULL değerine sahip bir nesne olarak kabul eder $null . Bu, başka bir dilden geliyorsanız bekleyebileceğinizden farklıdır.

$null örnekleri

Başlatmadığınız bir değişken kullanmayı denediğinizde, değeri şeklindedir $null. Bu, değerlerin kodunuz içine sızmasının $null en yaygın yollarından biridir.

PS> $null -eq $undefinedVariable
True

Bir değişken adını yanlış yazdığınızda PowerShell bunu farklı bir değişken olarak görür ve değeri olur $null.

Değerleri bulmanın $null diğer yolu, size hiçbir sonuç vermeyen diğer komutlardan gelmeleridir.

PS> function Get-Nothing {}
PS> $value = Get-Nothing
PS> $null -eq $value
True

$null etkisi

$null değerleri, kodunuzun nerede göründüğüne bağlı olarak farklı şekilde etkiler.

Dizelerde

Bir dizede kullanıyorsanız $null , bu boş bir değerdir (veya boş dizedir).

PS> $value = $null
PS> Write-Output "The value is $value"
The value is

Bu, günlük iletilerinde kullanırken değişkenlerin çevresine köşeli ayraç yerleştirmeyi sevmemin nedenlerinden biridir. Değer dizenin sonundayken değişken değerlerinizin kenarlarını tanımlamak daha da önemlidir.

PS> $value = $null
PS> Write-Output "The value is [$value]"
The value is []

Bu, boş dizelerin ve $null değerlerin kolayca tespit olmasını sağlar.

Sayısal denklemde

Sayısal denklemde bir $null değer kullanıldığında, hata vermezlerse sonuçlarınız geçersiz olur. Bazen olarak $null değerlendirilir 0 ve diğer zamanlarda sonucun $nulltamamını oluşturur. Burada, değerlerin sırasına bağlı olarak 0 veren $null çarpım içeren bir örnek verilmiştir.

PS> $null * 5
PS> $null -eq ( $null * 5 )
True

PS> 5 * $null
0
PS> $null -eq ( 5 * $null )
False

Koleksiyon yerine

Koleksiyon, değerlere erişmek için dizin kullanmanıza olanak tanır. Aslında nullolan bir koleksiyonda dizin oluşturmaya çalışırsanız şu hatayı alırsınız: Cannot index into a null array.

PS> $value = $null
PS> $value[10]
Cannot index into a null array.
At line:1 char:1
+ $value[10]
+ ~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArray

Bir koleksiyonunuz varsa ancak koleksiyonda olmayan bir öğeye erişmeye çalışırsanız, bir $null sonuç alırsınız.

$array = @( 'one','two','three' )
$null -eq $array[100]
True

Nesne yerine

Belirtilen özelliğe sahip olmayan bir nesnenin özelliğine veya alt özelliğine erişmeye çalışırsanız, tanımlanmamış bir $null değişken için yaptığınız gibi bir değer alırsınız. Değişkenin $null bu durumda gerçek bir nesne olup olmadığı önemli değildir.

PS> $null -eq $undefined.some.fake.property
True

PS> $date = Get-Date
PS> $null -eq $date.some.fake.property
True

Null değerli bir ifadedeki yöntem

Bir $null nesnede bir yöntemi çağırmak bir RuntimeExceptionoluşturur.

PS> $value = $null
PS> $value.toString()
You cannot call a method on a null-valued expression.
At line:1 char:1
+ $value.tostring()
+ ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

tümceciği You cannot call a method on a null-valued expression her gördüğüm zaman ilk aradığım şey, bir değişkende ilk olarak denetimi $nullolmadan bir yöntemi çağırdığım yerlerdir.

$null denetleniyor

Örneklerimi kontrol $null ederken her zaman sol tarafa yerleştirdiğim $null fark etmiş olabilirsiniz. Bu, kasıtlı olarak yapılır ve PowerShell en iyi uygulaması olarak kabul edilir. Sağa yerleştirmenin size beklenen sonucu vermediği bazı senaryolar vardır.

Sonraki örneğe bakın ve sonuçları tahmin etmeye çalışın:

if ( $value -eq $null )
{
    'The array is $null'
}
if ( $value -ne $null )
{
    'The array is not $null'
}

tanımlamazsam $value, ilki değerlendirilir $true ve iletimiz olur The array is $null. Buradaki tuzak, $value her ikisinin de $false

$value = @( $null )

Bu durumda, içeren $value bir dizidir $null. dizideki -eq her değeri denetler ve eşleşen değeri $null döndürür. Bu, olarak $falsedeğerlendirilir. , -ne eşleşmeyen $null her şeyi döndürür ve bu durumda sonuç yoktur (Bu, olarak da değerlendirilir $false). İkisi de olması $true gerektiği gibi görünse de.

her ikisinin de değerini olarak değerlendirmesini sağlayan bir değer oluşturmakla $falsedeğil, her ikisinin de olarak değerlendirdiği $truebir değer oluşturmak mümkündür. Mathias Jessen (@IISResetMe) bu senaryoya göz atan iyi bir gönderiye sahiptir.

PSScriptAnalyzer ve VSCode

PSScriptAnalyzer modülü, adlı PSPossibleIncorrectComparisonWithNullbu sorunu denetleen bir kurala sahiptir.

PS> Invoke-ScriptAnalyzer ./myscript.ps1

RuleName                              Message
--------                              -------
PSPossibleIncorrectComparisonWithNull $null should be on the left side of equality comparisons.

VS Code da PSScriptAnalyser kurallarını kullandığından, bunu betiğinizde bir sorun olarak vurgular veya tanımlar.

Basit if check

kişilerin $null olmayan bir değeri denetlemesinin yaygın bir yolu, karşılaştırma olmadan basit if() bir deyim kullanmaktır.

if ( $value )
{
    Do-Something
}

değer ise $null, bu değeri olarak $falsedeğerlendirilir. Bunu okumak kolaydır, ancak tam olarak ne aramasını beklediğiniz konusuna dikkat edin. Bu kod satırını şöyle okudum:

Bir değeri varsa $value .

Ama bütün hikaye bu değil. Bu satır aslında şunu söylüyor:

$null Değilse $value veya 0 veya $false boş bir dize ya da boş bir dizi.

Bu deyimin daha eksiksiz bir örneği aşağıda verilmiştir.

if ( $null -ne $value -and
        $value -ne 0 -and
        $value -ne '' -and
        ($value -isnot [array] -or $value.Length -ne 0) -and
        $value -ne $false )
{
    Do-Something
}

Bu diğer değerlerin sayıldığını ve yalnızca bir değişkenin değerinin $false olmadığını hatırladığınız sürece temel if bir denetim kullanmak son derece normaldir.

Birkaç gün önce bazı kodları yeniden düzenlediğimde bu sorunla karşılaştım. Bunun gibi temel bir özellik denetimi vardı.

if ( $object.property )
{
    $object.property = $value
}

Nesne özelliğine yalnızca varsa bir değer atamak istedim. Çoğu durumda, özgün nesnenin deyiminde if değerlendirilecek $true bir değeri vardı. Ancak bazen değerin ayarlanmamasıyla ilgili bir sorunla karşılaştım. Kodda hata ayıklaması yaptım ve nesnenin özelliğine sahip olduğunu ancak boş bir dize değeri olduğunu tespit ettim. Bu, önceki mantıkla güncelleştirilmesini engelledi. Bu yüzden uygun $null bir çek ekledim ve her şey işe yaradı.

if ( $null -ne $object.property )
{
    $object.property = $value
}

Bunun gibi küçük hataları tespit etmek zor ve için değerleri $nullagresif bir şekilde kontrol etmemi sağlar.

$null. Sayısı

Bir değer üzerindeki $null bir özelliğe erişmeye çalışırsanız, özelliği de $nullolur. count özelliği bu kuralın özel durumudur.

PS> $value = $null
PS> $value.count
0

Bir $null değeriniz olduğunda değeri count olur 0. Bu özel özellik PowerShell tarafından eklenir.

[PSCustomObject] Sayısı

PowerShell'deki neredeyse tüm nesneler bu count özelliğine sahiptir. Windows PowerShell 5.1'deki önemli bir özel durumdur [PSCustomObject] (Bu, PowerShell 6.0'da düzeltilir). Count özelliği olmadığından, kullanmayı denerseniz bir $null değer alırsınız. Çek yerine $null kullanmaya .Count çalışma diye buraya sesleniyorum.

Bu örneği Windows PowerShell 5.1 ve PowerShell 6.0'da çalıştırmak size farklı sonuçlar verir.

$value = [PSCustomObject]@{Name='MyObject'}
if ( $value.count -eq 1 )
{
    "We have a value"
}

Boş null

Diğerlerinden farklı davranan özel bir tür $null vardır. Boş olarak adlandıracağım $null ama aslında system.management.automation.internal.automationnull. Bu boş $null , hiçbir şey döndüren bir işlev veya betik bloğunun sonucu olarak elde ettiğiniz boş değerdir (geçersiz bir sonuç).

PS> function Get-Nothing {}
PS> $nothing = Get-Nothing
PS> $null -eq $nothing
True

ile $nullkarşılaştırırsanız bir $null değer alırsınız. Bir değerin gerekli olduğu bir değerlendirmede kullanıldığında, değer her zaman $nullşeklindedir. Ancak bir dizinin içine yerleştirirseniz, boş bir diziyle aynı şekilde değerlendirilir.

PS> $containempty = @( @() )
PS> $containnothing = @($nothing)
PS> $containnull = @($null)

PS> $containempty.count
0
PS> $containnothing.count
0
PS> $containnull.count
1

Bir $null değer içeren ve değeri count1olan bir diziniz olabilir. Ancak bir dizinin içine boş bir sonuç yerleştirirseniz, öğe olarak sayılmaz. Sayı şeklindedir 0.

Boş $null bir koleksiyon gibi davranırsanız, boştur.

Kesin olarak yazılmayan bir işlev parametresine boş bir değer geçirirseniz, PowerShell varsayılan olarak hiçbir şey değerini bir $null değere zorlamaz. Bu, işlevin içinde değerin System.Management.Automation.Internal.AutomationNull türü yerine olarak $null ele alınacağı anlamına gelir.

İşlem Hattı

Farkı gördüğünüz birincil yer, işlem hattının kullanılmasıdır. Bir değeri kanala $null alabilir, ancak boş $null bir değere yöneltemezsiniz.

PS> $null | ForEach-Object{ Write-Output 'NULL Value' }
'NULL Value'
PS> $nothing | ForEach-Object{ Write-Output 'No Value' }

Kodunuz bağlı olarak, mantığınızda öğesini $null hesaba bağlamanız gerekir.

önce kontrol edin $null

  • İşlem hattında null değerini filtreleme (... | Where {$null -ne $_} | ...)
  • İşlem hattı işlevinde işleme

foreach

En sevdiğim özelliklerden foreach biri, bir $null koleksiyonun üzerine numaralandırılmıyor olmasıdır.

foreach ( $node in $null )
{
    #skipped
}

Bu, numaralandırmadan önce koleksiyonu denetlemem gerekme $null neden olur. Bir değer koleksiyonunuz $null varsa, $node yine de olabilir $null.

Foreach, PowerShell 3.0 ile bu şekilde çalışmaya başladı. Daha eski bir sürüm kullanıyorsanız bu durum geçerli değildir. Bu, 2.0 uyumluluğu için kodu geri taşıma sırasında dikkat edilmesi gereken önemli değişikliklerden biridir.

Değer türleri

Teknik olarak, yalnızca başvuru türleri olabilir $null. Ancak PowerShell çok cömerttir ve değişkenlerin herhangi bir türde olmasını sağlar. Bir değer türünü kesin olarak yazmaya karar verirseniz, olamaz $null. PowerShell, $null birçok tür için varsayılan değere dönüştürür.

PS> [int]$number = $null
PS> $number
0

PS> [bool]$boolean = $null
PS> $boolean
False

PS> [string]$string = $null
PS> $string -eq ''
True

'den $nullgeçerli dönüştürmesi olmayan bazı türler vardır. Bu türler bir Cannot convert null to type hata oluşturur.

PS> [datetime]$date = $null
Cannot convert null to type "System.DateTime".
At line:1 char:1
+ [datetime]$date = $null
+ ~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : MetadataError: (:) [], ArgumentTransformationMetadataException
    + FullyQualifiedErrorId : RuntimeException

İşlev parametreleri

İşlev parametrelerinde kesin olarak belirlenmiş değerler kullanmak çok yaygındır. Genellikle betiklerimizdeki diğer değişken türlerini tanımlamama eğiliminde olsak bile parametrelerimizin türlerini tanımlamayı öğreniriz. İşlevlerinizde zaten kesin olarak belirlenmiş bazı değişkenleriniz olabilir ve bunun farkında bile olmayabilirsiniz.

function Do-Something
{
    param(
        [String] $Value
    )
}

Parametresinin türünü olarak stringayarladığınız anda değer hiçbir zaman olamaz $null. Bir değerin, kullanıcının bir değer sağıp sağlamadığını görmek için olup olmadığını denetlemek yaygın bir durumdur $null .

if ( $null -ne $Value ){...}

$Value hiçbir değer sağlanmayan boş bir dizedir '' . Bunun yerine otomatik değişkeni $PSBoundParameters.Value kullanın.

if ( $null -ne $PSBoundParameters.Value ){...}

$PSBoundParameters yalnızca işlev çağrıldığında belirtilen parametreleri içerir. Özelliğini denetlemek için yöntemini de kullanabilirsiniz ContainsKey .

if ( $PSBoundParameters.ContainsKey('Value') ){...}

IsNotNullOrEmpty

Değer bir dizeyse, değerin aynı anda boş bir dize olup olmadığını $null denetlemek için statik dize işlevini kullanabilirsiniz.

if ( -not [string]::IsNullOrEmpty( $value ) ){...}

Değer türünün bir dize olması gerektiğini bildiğimde kendimi bunu sık sık kullanıyorum.

Ne zaman kontrol $null

Savunma senaryosunu ben yapıyorum. Bir işlevi çağırıp bir değişkene atadığım her zaman için $nulldenetlenir.

$userList = Get-ADUser kevmar
if ($null -ne $userList){...}

kullanmayı veya foreach kullanmayı iftry/catchtercih ederim. Yanlış anlamadım, hala çok kullanıyorum try/catch . Ancak bir hata koşulu veya boş bir sonuç kümesi için test edebilirsem, özel durum işlememin gerçek özel durumlar için olmasını sağlayabilirim.

Ayrıca, bir nesnedeki bir değere dizin oluşturmadan veya yöntemleri çağırmadan önce de denetleme $null eğilimindeyim. Bu iki eylem bir $null nesne için başarısız olduğundan önce bunları doğrulamayı önemli buluyorum. Bu senaryoları bu gönderinin başlarında zaten ele aldım.

Sonuç senaryosu yok

Farklı işlevlerin ve komutların sonuç yok senaryolarını farklı işlediğini bilmeniz önemlidir. Birçok PowerShell komutu boş $null ve hata akışında bir hata döndürür. Ancak diğerleri özel durumlar oluşturur veya size bir durum nesnesi verir. Kullandığınız komutların sonuç yok ve hata senaryolarıyla nasıl başa çıkdığını öğrenmek yine size kalmış.

$null başlat

Aldığım bir alışkanlık, tüm değişkenlerimi kullanmadan önce başlatmaktır. Bunu başka dillerde yapmanız gerekir. İşlevimin en üstünde veya foreach döngüsüne girerken kullandığım tüm değerleri tanımlarım.

İşte size yakından bakmanızı istediğim bir senaryo. Daha önce takip etmek zorunda kaldığım bir hata örneği.

function Do-Something
{
    foreach ( $node in 1..6 )
    {
        try
        {
            $result = Get-Something -ID $node
        }
        catch
        {
            Write-Verbose "[$result] not valid"
        }

        if ( $null -ne $result )
        {
            Update-Something $result
        }
    }
}

Buradaki beklenti, bir sonuç veya boş $nullbir sonuç döndürmektirGet-Something. Hata varsa günlüğe kaydederiz. Ardından işlemeden önce geçerli bir sonuç aldığımızdan emin olmak için kontrol ederiz.

Bu kodda gizlenen hata, Get-Something bir özel durum oluşturur ve değerine $resultdeğer atamaz. Atamadan önce başarısız olur, bu nedenle değişkene $result atama $null bile gerçekleştirmeyiz. $result yine de diğer yinelemelerden önceki geçerli $result değerleri içerir. Update-Something bu örnekte aynı nesne üzerinde birden çok kez yürütmek için.

Bu sorunu azaltmak için kullanmadan önce foreach döngüsünün hemen içine ayarliyorum $result$null .

foreach ( $node in 1..6 )
{
    $result = $null
    try
    {
        ...

Kapsam sorunları

Bu, kapsam belirleme sorunlarının azaltılmasına da yardımcı olur. Bu örnekte, döngüde değerleri tekrar $result tekrar atarız. Ancak PowerShell işlevin dışındaki değişken değerlerin geçerli işlevin kapsamına taşmasına izin verdiğinden, bunları işlevinizin içinde başlatmak, bu şekilde ortaya konabilecek hataları azaltır.

İşlevinizdeki başlatılmamış bir değişken, üst kapsamdaki bir değere ayarlanmışsa değildir $null . Üst kapsam, işlevinizi çağıran ve aynı değişken adlarını kullanan başka bir işlev olabilir.

Aynı Do-something örneği alır ve döngüsü kaldırırsam şu örneğe benzer bir sonuçla sonuçlanırsam:

function Invoke-Something
{
    $result = 'ParentScope'
    Do-Something
}

function Do-Something
{
    try
    {
        $result = Get-Something -ID $node
    }
    catch
    {
        Write-Verbose "[$result] not valid"
    }

    if ( $null -ne $result )
    {
        Update-Something $result
    }
}

Çağrısı Get-Something bir özel durum oluşturursa, denetimim $null$result öğesini bulur Invoke-Something. İşlevinizin içindeki değerin başlatılması bu sorunu azaltır.

Değişkenleri adlandırmak zordur ve bir yazarın birden çok işlevde aynı değişken adlarını kullanması yaygındır. Her zaman kullandığımı $node$result$data biliyorum. Bu nedenle, farklı kapsamlardaki değerlerin olmaması gereken yerlerde gösterilmesi çok kolay olacaktır.

Çıktıyı $null yeniden yönlendirme

Bu makalenin tamamı için değerlerden bahsediyorum $null ancak çıktıyı 'a $nullyeniden yönlendirmeden bahsetmediysem konu tamamlanmamıştır. Bazı durumlarda, gizlemesini istediğiniz bilgilerin veya nesnelerin çıkışını veren komutlarınız vardır. Çıktıyı adresine $null yönlendirmek bunu yapar.

Out-Null

Out-Null komutu, işlem hattı verilerini $nullöğesine yeniden yönlendirmenin yerleşik yoludur.

New-Item -Type Directory -Path $path | Out-Null

$null atama

komutunun sonuçlarını kullanarak Out-Nullaynı etki için öğesine $null atayabilirsiniz.

$null = New-Item -Type Directory -Path $path

$null Sabit bir değer olduğundan, hiçbir zaman üzerine yazasınız. Kodumda görünme şeklini beğenmedim ama genellikle değerinden Out-Nulldaha hızlı çalışır.

$null'a yeniden yönlendirme

Çıktıyı adresine göndermek için yeniden yönlendirme işlecini $nullde kullanabilirsiniz.

New-Item -Type Directory -Path $path > $null

Farklı akışlarda çıkış veren komut satırı yürütülebilir dosyalarıyla ilgileniyorsanız. Tüm çıkış akışlarını $null şu şekilde yeniden yönlendirebilirsiniz:

git status *> $null

Özet

Bu konuda çok fazla şey ele aldım ve bu makalenin derin bakışlarımdan daha parçalı olduğunu biliyorum. Bunun nedeni $null , değerlerin PowerShell'de birçok farklı yerde açılabilir olması ve tüm nüansların onu bulduğunuz yere özel olmasıdır. Umarım karşılaşabileceğiniz daha belirsiz senaryoları daha iyi anlayıp $null farkındalığınızla bu durumdan uzaklaşırsınız.