$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 $null
tamamı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 null
olan 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 RuntimeException
oluş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 $null
olmadan 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 $false
değ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 $false
değil, her ikisinin de olarak değerlendirdiği $true
bir 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ı PSPossibleIncorrectComparisonWithNull
bu 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 $false
değ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
veya0
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 $null
agresif 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 $null
olur. 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 $null
karşı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 count
1
olan 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 $null
geç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 string
ayarladığı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 $null
denetlenir.
$userList = Get-ADUser kevmar
if ($null -ne $userList){...}
kullanmayı veya foreach
kullanmayı if
try/catch
tercih 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ş $null
bir 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 $result
değ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 $null
yeniden 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-Null
aynı 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-Null
daha hızlı çalışır.
$null'a yeniden yönlendirme
Çıktıyı adresine göndermek için yeniden yönlendirme işlecini $null
de 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.
PowerShell
Geri Bildirim
https://aka.ms/ContentUserFeedback.
Çok yakında: 2024 boyunca, içerik için geri bildirim mekanizması olarak GitHub Sorunları’nı kullanımdan kaldıracak ve yeni bir geri bildirim sistemiyle değiştireceğiz. Daha fazla bilgi için bkz.Gönderin ve geri bildirimi görüntüleyin