Semua yang ingin Anda ketahui tentang $null
PowerShell $null
sering tampak sederhana tetapi memiliki banyak nuansa. Mari kita lihat $null
lebih dekat sehingga Anda tahu apa yang terjadi ketika Anda secara tak terduga mengalami $null
nilai.
Catatan
Versi asli artikel ini muncul di blog yang ditulis oleh @KevinMarquette. Tim PowerShell berterima kasih kepada Kevin karena telah membagikan konten ini kepada kami. Silakan lihat blognya di PowerShellExplained.com.
Apa itu NULL?
Anda dapat menganggap NULL sebagai nilai yang tidak diketahui atau kosong. Variabel adalah NULL hingga Anda menetapkan nilai atau objek ke dalamnya. Ini bisa penting karena ada beberapa perintah yang memerlukan nilai dan menghasilkan kesalahan jika nilainya NULL.
$null PowerShell
$null
adalah variabel otomatis dalam PowerShell yang digunakan untuk mewakili NULL. Anda dapat menetapkannya ke variabel, menggunakannya sebagai perbandingan dan menggunakannya sebagai place holder untuk NULL dalam koleksi.
PowerShell memperlakukan $null
sebagai objek dengan nilai NULL. Ini berbeda dari yang mungkin Anda harapkan jika Anda berasal dari bahasa lain.
Contoh $null
Setiap kali Anda mencoba menggunakan variabel yang belum Anda inisialisasi, nilainya adalah $null
. Ini adalah salah satu cara paling umum yang $null
nilainya masuk ke dalam kode Anda.
PS> $null -eq $undefinedVariable
True
Jika Anda salah ketik nama variabel, PowerShell melihatnya sebagai variabel yang berbeda dan nilainya adalah $null
.
Cara lain Anda menemukan $null
nilai adalah ketika nilai tersebut berasal dari perintah lain yang tidak memberi Anda hasil apa pun.
PS> function Get-Nothing {}
PS> $value = Get-Nothing
PS> $null -eq $value
True
Dampak $null
$null
nilai berdampak pada kode Anda secara berbeda tergantung di mana nilai tersebut muncul.
Dalam string
Jika Anda menggunakan $null
dalam string, maka itu adalah nilai kosong (atau string kosong).
PS> $value = $null
PS> Write-Output "The value is $value"
The value is
Ini adalah salah satu alasan saya suka menempatkan tanda kurung siku di sekitar variabel saat menggunakannya dalam pesan log. Lebih penting lagi untuk mengidentifikasi tepi nilai variabel Anda saat nilai berada di akhir string.
PS> $value = $null
PS> Write-Output "The value is [$value]"
The value is []
Ini membuat string dan $null
nilai kosong mudah ditemukan.
Dalam persamaan numerik
$null
Ketika nilai digunakan dalam persamaan numerik, hasil Anda tidak valid jika tidak memberikan kesalahan. $null
Kadang-kadang mengevaluasi ke 0
dan di lain waktu itu membuat seluruh hasilnya $null
.
Berikut adalah contoh dengan perkalian yang memberikan 0 atau $null
tergantung pada urutan nilai.
PS> $null * 5
PS> $null -eq ( $null * 5 )
True
PS> 5 * $null
0
PS> $null -eq ( 5 * $null )
False
Menggantikan koleksi
Koleksi memungkinkan Anda menggunakan indeks untuk mengakses nilai. Jika Anda mencoba mengindeks ke dalam koleksi yang sebenarnya null
, Anda mendapatkan kesalahan ini: 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
Jika Anda memiliki koleksi tetapi mencoba mengakses elemen yang tidak ada dalam koleksi, Anda mendapatkan $null
hasilnya.
$array = @( 'one','two','three' )
$null -eq $array[100]
True
Menggantikan objek
Jika Anda mencoba mengakses properti atau sub properti objek yang tidak memiliki properti yang ditentukan, Anda mendapatkan $null
nilai seperti yang Anda lakukan untuk variabel yang tidak ditentukan. Tidak masalah jika variabel adalah $null
atau objek aktual dalam kasus ini.
PS> $null -eq $undefined.some.fake.property
True
PS> $date = Get-Date
PS> $null -eq $date.some.fake.property
True
Metode pada ekspresi bernilai null
Memanggil metode pada $null
objek melempar .RuntimeException
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
Setiap kali saya melihat frasa You cannot call a method on a null-valued expression
, maka hal pertama yang saya cari adalah tempat di mana saya memanggil metode pada variabel tanpa terlebih dahulu memeriksanya untuk $null
.
Memeriksa $null
Anda mungkin telah memperhatikan bahwa saya selalu menempatkan $null
di sebelah kiri saat memeriksa $null
dalam contoh saya. Ini disengaja dan diterima sebagai praktik terbaik PowerShell. Ada beberapa skenario di mana menempatkannya di sebelah kanan tidak memberi Anda hasil yang diharapkan.
Lihat contoh berikutnya ini dan coba prediksi hasilnya:
if ( $value -eq $null )
{
'The array is $null'
}
if ( $value -ne $null )
{
'The array is not $null'
}
Jika saya tidak mendefinisikan $value
, yang pertama mengevaluasi ke $true
dan pesan kami adalah The array is $null
. Perangkap di sini adalah bahwa adalah mungkin untuk membuat $value
yang memungkinkan keduanya menjadi $false
$value = @( $null )
Dalam hal ini, $value
adalah array yang berisi $null
. Memeriksa -eq
setiap nilai dalam array dan mengembalikan $null
yang cocok. Ini mengevaluasi ke $false
. mengembalikan -ne
semua yang tidak cocok $null
dan dalam hal ini tidak ada hasil (Ini juga mengevaluasi ke $false
). Tidak satu $true
pun meskipun terlihat seperti salah satu dari mereka seharusnya.
Kita tidak hanya dapat membuat nilai yang membuat keduanya dievaluasi ke $false
, dimungkinkan untuk membuat nilai di mana mereka berdua mengevaluasi ke $true
. Mathias Jessen (@IISResetMe) memiliki postingan bagus yang menyelami skenario tersebut.
PSScriptAnalyzer dan VSCode
Modul PSScriptAnalyzer memiliki aturan yang memeriksa masalah ini yang disebut PSPossibleIncorrectComparisonWithNull
.
PS> Invoke-ScriptAnalyzer ./myscript.ps1
RuleName Message
-------- -------
PSPossibleIncorrectComparisonWithNull $null should be on the left side of equality comparisons.
Karena Visual Studio Code juga menggunakan aturan PSScriptAnalyser, visual ini juga menyoroti atau mengidentifikasi ini sebagai masalah dalam skrip Anda.
Sederhana jika diperiksa
Cara umum bahwa orang memeriksa nilai non-$null adalah dengan menggunakan pernyataan sederhana if()
tanpa perbandingan.
if ( $value )
{
Do-Something
}
Jika nilainya adalah $null
, ini mengevaluasi ke $false
. Ini mudah dibaca, tetapi berhati-hatilah bahwa ia mencari persis apa yang Anda harapkan untuk dicari. Saya membaca baris kode tersebut sebagai:
Jika
$value
memiliki nilai.
Tapi itu bukan seluruh cerita. Baris itu benar-benar mengatakan:
Jika
$value
bukan$null
atau0
atau$false
atau string kosong atau array kosong.
Berikut adalah sampel pernyataan yang lebih lengkap.
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
}
Sangat OK untuk menggunakan pemeriksaan dasar if
selama Anda mengingat nilai-nilai lain dihitung sebagai $false
dan bukan hanya variabel yang memiliki nilai.
Saya mengalami masalah ini ketika merefaktor beberapa kode beberapa hari yang lalu. Ini memiliki pemeriksaan properti dasar seperti ini.
if ( $object.property )
{
$object.property = $value
}
Saya ingin menetapkan nilai ke properti objek hanya jika ada. Dalam kebanyakan kasus, objek asli memiliki nilai yang akan dievaluasi $true
dalam if
pernyataan. Tapi aku mengalami masalah di mana nilainya kadang-kadang tidak diatur. Saya men-debug kode dan menemukan bahwa objek memiliki properti tetapi itu adalah nilai string kosong. Hal ini mencegahnya diperbarui dengan logika sebelumnya. Jadi saya menambahkan pemeriksaan yang tepat $null
dan semuanya bekerja.
if ( $null -ne $object.property )
{
$object.property = $value
}
Ini adalah bug kecil seperti ini yang sulit ditemukan dan membuat saya secara agresif memeriksa nilai untuk $null
.
$null. Menghitung
Jika Anda mencoba mengakses properti pada $null
nilai, properti tersebut juga $null
. Properti count
adalah pengecualian untuk aturan ini.
PS> $value = $null
PS> $value.count
0
Ketika Anda memiliki $null
nilai, maka count
adalah 0
. Properti khusus ini ditambahkan oleh PowerShell.
[PSCustomObject] Menghitung
Hampir semua objek di PowerShell memiliki properti hitungan tersebut. Salah satu pengecualian penting adalah [PSCustomObject]
di Windows PowerShell 5.1 (Ini diperbaiki di PowerShell 6.0). Ini tidak memiliki properti hitungan sehingga Anda mendapatkan $null
nilai jika Anda mencoba menggunakannya. Saya menyebutnya di sini sehingga Anda tidak mencoba untuk menggunakan .Count
alih-alih $null
cek.
Menjalankan contoh ini di Windows PowerShell 5.1 dan PowerShell 6.0 memberi Anda hasil yang berbeda.
$value = [PSCustomObject]@{Name='MyObject'}
if ( $value.count -eq 1 )
{
"We have a value"
}
Enumerable null
Ada satu jenis $null
khusus yang bertindak berbeda dari yang lain. Saya akan menyebutnya null yang dapat dijumlahkan tetapi itu benar-benar System.Management.Automation.Internal.AutomationNull.
Null yang dapat dijumlahkan ini adalah yang Anda dapatkan sebagai hasil dari fungsi atau blok skrip yang tidak mengembalikan apa pun (hasil yang batal).
PS> function Get-Nothing {}
PS> $nothing = Get-Nothing
PS> $null -eq $nothing
True
Jika Anda membandingkannya dengan $null
, Anda mendapatkan $null
nilai. Saat digunakan dalam evaluasi di mana nilai diperlukan, nilainya selalu $null
. Tetapi jika Anda menempatkannya di dalam array, itu diperlakukan sama dengan array kosong.
PS> $containempty = @( @() )
PS> $containnothing = @($nothing)
PS> $containnull = @($null)
PS> $containempty.count
0
PS> $containnothing.count
0
PS> $containnull.count
1
Anda dapat memiliki array yang berisi satu $null
nilai dan nilainya count
adalah 1
. Tetapi jika Anda menempatkan array kosong di dalam array, maka array tersebut tidak dihitung sebagai item. Hitungannya adalah 0
.
Jika Anda memperlakukan null yang dapat dijumlahkan seperti koleksi, maka kosong.
Jika Anda meneruskan null yang dapat dijumlahkan ke parameter fungsi yang tidak ditik dengan kuat, PowerShell memaksa null yang dapat dijumlahkan ke dalam $null
nilai secara default. Ini berarti di dalam fungsi, nilai diperlakukan sebagai $null
alih-alih jenis System.Management.Automation.Internal.AutomationNull .
Alur
Tempat utama yang Anda lihat perbedaannya adalah saat menggunakan alur. Anda dapat menyalurkan $null
nilai tetapi bukan nilai null yang dapat dijumlahkan.
PS> $null | ForEach-Object{ Write-Output 'NULL Value' }
'NULL Value'
PS> $nothing | ForEach-Object{ Write-Output 'No Value' }
Bergantung pada kode Anda, Anda harus memperhitungkan $null
dalam logika Anda.
Periksa terlebih $null
dahulu
- Memfilter null pada alur (
... | Where {$null -ne $_} | ...
) - Menanganinya dalam fungsi alur
foreach
Salah satu fitur foreach
favorit saya adalah bahwa itu tidak menghitung koleksi $null
.
foreach ( $node in $null )
{
#skipped
}
Ini menyelamatkan saya dari harus $null
memeriksa koleksi sebelum saya menghitungnya. Jika Anda memiliki kumpulan $null
nilai, $node
masih bisa .$null
Foreach mulai bekerja dengan cara ini dengan PowerShell 3.0. Jika Anda kebetulan berada di versi yang lebih lama, maka ini tidak terjadi. Ini adalah salah satu perubahan penting yang perlu diperhatikan ketika kode port kembali untuk kompatibilitas 2.0.
Jenis nilai
Secara teknis, hanya jenis referensi yang dapat berupa $null
. Tetapi PowerShell sangat murah hati dan memungkinkan variabel menjadi jenis apa pun. Jika Anda memutuskan untuk mengetik jenis nilai dengan kuat, itu tidak boleh $null
.
PowerShell mengonversi $null
ke nilai default untuk banyak jenis.
PS> [int]$number = $null
PS> $number
0
PS> [bool]$boolean = $null
PS> $boolean
False
PS> [string]$string = $null
PS> $string -eq ''
True
Ada beberapa jenis yang tidak memiliki konversi yang valid dari $null
. Jenis ini menghasilkan Cannot convert null to type
kesalahan.
PS> [datetime]$date = $null
Cannot convert null to type "System.DateTime".
At line:1 char:1
+ [datetime]$date = $null
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
+ FullyQualifiedErrorId : RuntimeException
Parameter fungsi
Menggunakan nilai yang sangat ditik dalam parameter fungsi sangat umum. Kita umumnya belajar mendefinisikan jenis parameter kita bahkan jika kita cenderung tidak menentukan jenis variabel lain dalam skrip kita. Anda mungkin sudah memiliki beberapa variabel yang sangat ditik dalam fungsi Anda dan bahkan tidak menyadarinya.
function Do-Something
{
param(
[String] $Value
)
}
Segera setelah Anda mengatur jenis parameter sebagai string
, nilainya tidak pernah bisa $null
. Adalah umum untuk memeriksa apakah nilai adalah $null
untuk melihat apakah pengguna memberikan nilai atau tidak.
if ( $null -ne $Value ){...}
$Value
adalah string ''
kosong ketika tidak ada nilai yang disediakan. Gunakan variabel $PSBoundParameters.Value
otomatis sebagai gantinya.
if ( $null -ne $PSBoundParameters.Value ){...}
$PSBoundParameters
hanya berisi parameter yang ditentukan ketika fungsi dipanggil.
Anda juga dapat menggunakan ContainsKey
metode untuk memeriksa properti.
if ( $PSBoundParameters.ContainsKey('Value') ){...}
IsNotNullOrEmpty
Jika nilainya adalah string, Anda dapat menggunakan fungsi string statis untuk memeriksa apakah nilainya adalah $null
atau string kosong secara bersamaan.
if ( -not [string]::IsNullOrEmpty( $value ) ){...}
Saya sering menggunakan ini ketika saya tahu jenis nilainya harus berupa string.
Ketika saya $null memeriksa
Saya seorang skrip defensif. Setiap kali saya memanggil fungsi dan menetapkannya ke variabel, saya memeriksanya untuk $null
.
$userList = Get-ADUser kevmar
if ($null -ne $userList){...}
Saya lebih suka menggunakan if
atau foreach
lebih menggunakan try/catch
. Jangan salah, aku masih sering menggunakannya try/catch
. Tetapi jika saya dapat menguji kondisi kesalahan atau serangkaian hasil kosong, saya dapat mengizinkan penanganan pengecualian saya untuk pengecualian yang benar.
Saya juga cenderung memeriksa sebelum saya mengindeks $null
ke dalam nilai atau metode panggilan pada objek. Kedua tindakan ini gagal untuk objek $null
jadi saya merasa penting untuk memvalidasinya terlebih dahulu. Saya sudah membahas skenario tersebut sebelumnya dalam posting ini.
Tidak ada skenario hasil
Penting untuk diketahui bahwa berbagai fungsi dan perintah menangani skenario tidak ada hasil secara berbeda. Banyak perintah PowerShell mengembalikan null yang dapat dijumlahkan dan kesalahan dalam aliran kesalahan. Tetapi orang lain melemparkan pengecualian atau memberi Anda objek status. Masih terserah Anda untuk mengetahui bagaimana perintah yang Anda gunakan menangani skenario tidak ada hasil dan kesalahan.
Menginisialisasi ke $null
Salah satu kebiasaan yang saya ambil adalah menginisialisasi semua variabel saya sebelum saya menggunakannya. Anda diharuskan melakukan ini dalam bahasa lain. Di bagian atas fungsi saya atau saat saya memasukkan perulangan foreach, saya menentukan semua nilai yang saya gunakan.
Berikut adalah skenario yang saya ingin Anda untuk melihat lebih dekat. Ini contoh bug yang harus kukejar sebelumnya.
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
}
}
}
Harapan di sini adalah bahwa Get-Something
mengembalikan hasil atau null yang dapat dijumlahkan. Jika ada kesalahan, kami mencatatnya. Kemudian kami memeriksa untuk memastikan kami mendapatkan hasil yang valid sebelum memprosesnya.
Bug yang bersembunyi dalam kode ini adalah ketika Get-Something
melemparkan pengecualian dan tidak menetapkan nilai ke $result
. Ini gagal sebelum penugasan sehingga kami bahkan tidak menetapkan $null
ke $result
variabel. $result
masih berisi valid $result
sebelumnya dari iterasi lain.
Update-Something
untuk menjalankan beberapa kali pada objek yang sama dalam contoh ini.
Saya mengatur $result
ke $null
kanan di dalam perulangan foreach sebelum saya menggunakannya untuk mengurangi masalah ini.
foreach ( $node in 1..6 )
{
$result = $null
try
{
...
Masalah cakupan
Ini juga membantu mengurangi masalah cakupan. Dalam contoh itu, kami menetapkan nilai untuk $result
berulang kali dalam perulangan. Tetapi karena PowerShell memungkinkan nilai variabel dari luar fungsi untuk berdarah ke dalam cakupan fungsi saat ini, menginisialisasinya di dalam fungsi Anda mengurangi bug yang dapat diperkenalkan seperti itu.
Variabel yang tidak diinisialisasi dalam fungsi Anda bukan $null
jika diatur ke nilai dalam cakupan induk.
Cakupan induk bisa menjadi fungsi lain yang memanggil fungsi Anda dan menggunakan nama variabel yang sama.
Jika saya mengambil contoh yang sama Do-something
dan menghapus perulangan, saya akan berakhir dengan sesuatu yang terlihat seperti contoh ini:
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
}
}
Jika panggilan untuk Get-Something
melemparkan pengecualian, maka pemeriksaan saya $null
menemukan $result
dari Invoke-Something
. Menginisialisasi nilai di dalam fungsi Anda mengurangi masalah ini.
Penamaan variabel sulit dan umum bagi penulis untuk menggunakan nama variabel yang sama dalam beberapa fungsi. Aku tahu aku menggunakan $node
,$result
,$data
sepanjang waktu. Jadi akan sangat mudah bagi nilai dari cakupan yang berbeda untuk muncul di tempat-tempat di mana mereka seharusnya tidak berada.
Mengalihkan output ke $null
Saya telah berbicara tentang $null
nilai untuk seluruh artikel ini tetapi topik tidak lengkap jika saya tidak menyebutkan mengalihkan output ke $null
. Ada kalanya Anda memiliki perintah yang menghasilkan informasi atau objek yang ingin Anda tekan. Mengalihkan output untuk $null
melakukan itu.
Out-Null
Perintah Out-Null adalah cara bawaan untuk mengalihkan data alur ke $null
.
New-Item -Type Directory -Path $path | Out-Null
Tetapkan ke $null
Anda dapat menetapkan hasil perintah untuk $null
efek yang sama seperti menggunakan Out-Null
.
$null = New-Item -Type Directory -Path $path
Karena $null
merupakan nilai konstanta, Anda tidak pernah bisa menimpanya. Saya tidak suka tampilannya dalam kode saya tetapi sering berkinerja lebih cepat daripada Out-Null
.
Mengalihkan ke $null
Anda juga dapat menggunakan operator pengalihan untuk mengirim output ke $null
.
New-Item -Type Directory -Path $path > $null
Jika Anda berurusan dengan executable baris perintah yang menghasilkan pada aliran yang berbeda. Anda dapat mengalihkan semua aliran output ke $null
seperti ini:
git status *> $null
Ringkasan
Saya membahas banyak dasar tentang hal ini dan saya tahu artikel ini lebih terfragmentasi daripada sebagian besar penyelaman mendalam saya. Itu karena $null
nilai dapat muncul di berbagai tempat di PowerShell dan semua nuansa khusus untuk tempat Anda menemukannya. Saya harap Anda menjauh dari ini dengan pemahaman $null
yang lebih baik dan kesadaran tentang skenario yang lebih tidak jelas yang mungkin Anda alami.