Minden, amit tudni akart $null
A PowerShell $null
gyakran egyszerűnek tűnik, de sok árnyalata van. Vessünk egy pillantást $null
, hogy tudjuk, mi történik, ha váratlanul belefut egy $null
értékbe.
Feljegyzés
A cikk eredeti verziója @KevinMarquette által írt blogon jelent meg. A PowerShell csapata köszönjük Kevinnek, hogy megosztotta velünk ezt a tartalmat. Kérjük, nézze meg a blogját a PowerShellExplained.com.
Mi az a NULL?
A NULL érték ismeretlen vagy üres értékként is felfogható. A változó null értékű, amíg hozzá nem rendel egy értéket vagy objektumot. Ez azért lehet fontos, mert vannak olyan parancsok, amelyekhez értékre van szükség, és hibaüzeneteket generálnak, ha az érték NULL.
PowerShell-$null
$null
egy automatikus változó a PowerShellben, amely a NULL értéket jelöli. Hozzárendelheti a változókhoz, összehasonlításban használhatja, és a NULL helyőrzőjeként használhatja egy gyűjteményben.
A PowerShell null értékű objektumként kezeli $null
. Ez eltér attól, amit elvárhat, ha más nyelvről származik.
Példák $null
Amikor olyan változót próbál használni, amelyet nem inicializált, az érték a következő $null
. Ez az egyik leggyakoribb módszer, amellyel $null
az értékek belopódnak a kódba.
PS> $null -eq $undefinedVariable
True
Ha véletlenül tévesen írja be a változó nevét, akkor a PowerShell más változóként látja, és az érték az $null
.
A másik módszer az értékek megkeresése $null
, ha más parancsokból származnak, amelyek nem adnak eredményt.
PS> function Get-Nothing {}
PS> $value = Get-Nothing
PS> $null -eq $value
True
A $null hatása
$null
az értékek eltérően befolyásolják a kódot attól függően, hogy hol jelennek meg.
Sztringekben
Ha sztringben használja $null
, akkor az üres érték (vagy üres sztring).
PS> $value = $null
PS> Write-Output "The value is $value"
The value is
Ez az egyik oka annak, hogy a változók köré szögletes zárójeleket szeretnék elhelyezni, amikor naplóüzenetekben használják őket. Még fontosabb azonosítani a változóértékek széleit, ha az érték a sztring végén van.
PS> $value = $null
PS> Write-Output "The value is [$value]"
The value is []
Így az üres sztringek és $null
értékek könnyen felismerhetőek.
Numerikus egyenletben
Ha egy $null
numerikus egyenletben értéket használ, az eredmények érvénytelenek lesznek, ha nem adnak hibát. Néha a $null
kiértékelés eredménye 0
, máskor pedig a teljes eredmény $null
.
Íme egy példa a szorzásra, amely 0 értéket ad, vagy $null
az értékek sorrendjétől függően.
PS> $null * 5
PS> $null -eq ( $null * 5 )
True
PS> 5 * $null
0
PS> $null -eq ( 5 * $null )
False
Gyűjtemény helyett
A gyűjtemények segítségével index használatával érheti el az értékeket. Ha valójában null
egy gyűjteménybe próbál indexelni, a következő hibaüzenet jelenik meg: 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
Ha rendelkezik gyűjteménysel, de megpróbál hozzáférni egy olyan elemhez, amely nem szerepel a gyűjteményben, eredményt kap $null
.
$array = @( 'one','two','three' )
$null -eq $array[100]
True
Objektum helyett
Ha olyan objektum tulajdonságához vagy altulajdonságához próbál hozzáférni, amely nem rendelkezik a megadott tulajdonságmal, egy olyan értéket kap $null
, mint egy definiálatlan változó esetében. Ebben az esetben nem számít, hogy a $null
változó vagy egy tényleges objektum.
PS> $null -eq $undefined.some.fake.property
True
PS> $date = Get-Date
PS> $null -eq $date.some.fake.property
True
Metódus null értékű kifejezésen
Egy metódus meghívása egy $null
objektumon egy 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
Amikor látom a kifejezést You cannot call a method on a null-valued expression
, akkor az első dolog, amit keresek, azok a helyek, ahol egy metódust hívok meg egy változón anélkül, hogy először ellenőrizném $null
.
$null ellenőrzése
Lehet, hogy észrevette, hogy én mindig a $null
bal oldalon, amikor ellenőrzi $null
az én példákat. Ez szándékos, és a PowerShell ajánlott eljárása. Vannak olyan helyzetek, amikor a jobb oldalon való elhelyezés nem adja meg a várt eredményt.
Tekintse meg ezt a következő példát, és próbálja meg előrejelezni az eredményeket:
if ( $value -eq $null )
{
'The array is $null'
}
if ( $value -ne $null )
{
'The array is not $null'
}
Ha nem határozom meg $value
, az első kiértékeli , $true
és az üzenetünk az The array is $null
. Itt az a csapda, hogy létrehozható egy $value
olyan, amely lehetővé teszi, hogy mindkettő $false
$value = @( $null )
Ebben az esetben a $value
tömb egy .$null
A -eq
tömb minden értékét ellenőrzi, és a $null
megfeleltetés értékét adja vissza. Ez a kiértékelés eredménye.$false
A -ne
visszaad mindent, ami nem egyezik, $null
és ebben az esetben nincsenek eredmények (Ez is kiértékeli).$false
Egyik $true
sem annak ellenére, hogy úgy néz ki, hogy az egyiknek kell lennie.
Nem csak olyan értéket hozhatunk létre, amely mindkettőt kiértékeli $false
, hanem olyan értéket is létrehozhatunk, amelyben mindketten kiértékelik őket $true
. Mathias Jessen (@IISResetMe) van egy jó post , hogy merüljön el, hogy a forgatókönyv.
PSScriptAnalyzer és VSCode
A PSScriptAnalyzer modul rendelkezik egy szabálysal, amely ellenőrzi ezt a problémát.PSPossibleIncorrectComparisonWithNull
PS> Invoke-ScriptAnalyzer ./myscript.ps1
RuleName Message
-------- -------
PSPossibleIncorrectComparisonWithNull $null should be on the left side of equality comparisons.
Mivel a VS Code a PSScriptAnalyser-szabályokat is használja, a szkriptben ezt a problémát is kiemeli vagy azonosítja.
Egyszerű, ha van ellenőrzés
A nem $null értékek ellenőrzésének gyakori módja egy egyszerű if()
állítás használata összehasonlítás nélkül.
if ( $value )
{
Do-Something
}
Ha az érték az $null
, akkor a kiértékelés eredménye a következő lesz $false
: . Ez könnyen olvasható, de legyen óvatos, hogy pontosan azt keresi, amit vár. Ezt a kódsort a következőképpen olvastam:
Ha
$value
van értéke.
De nem ez az egész történet. Ez a sor valójában a következőt mondja:
Ha
$value
nem$null
, vagy0
$false
üres sztring vagy üres tömb.
Íme egy teljesebb példa erre az utasításra.
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
}
Teljesen rendben van az alapszintű if
ellenőrzés használata, ha emlékszik a többi értékre $false
, és nem csak arra, hogy egy változónak van értéke.
Néhány nappal ezelőtt egy kód újrabontásakor belefutottam ebbe a problémába. Ehhez hasonló alaptulajdonság-ellenőrzést kapott.
if ( $object.property )
{
$object.property = $value
}
Csak akkor akartam értéket hozzárendelni az objektumtulajdonsághoz, ha létezik. A legtöbb esetben az eredeti objektum olyan értékkel rendelkezik, amely kiértékelhető $true
az if
utasításban. De belefutottam egy olyan problémába, ahol az érték időnként nem lett beállítva. Hibakeresést észleltem a kódon, és megállapítottam, hogy az objektum rendelkezik a tulajdonságmal, de üres sztringérték volt. Ez megakadályozta, hogy valaha is frissüljön az előző logikával. Ezért hozzáadtam egy megfelelő $null
ellenőrzést, és minden működött.
if ( $null -ne $object.property )
{
$object.property = $value
}
Ez a kis hibák, mint ezek, amelyek nehéz észrevenni, és hogy én agresszíven ellenőrizze értékek .$null
$null. Számít
Ha megpróbál hozzáférni egy tulajdonsághoz egy $null
értéken, akkor a tulajdonság is $null
. A count
tulajdonság kivételt képez a szabály alól.
PS> $value = $null
PS> $value.count
0
Ha van egy $null
érték, akkor a count
.0
Ezt a speciális tulajdonságot a PowerShell hozzáadja.
[PSCustomObject] Számít
A PowerShell szinte minden objektuma rendelkezik ezzel a count tulajdonságmal. Az egyik fontos kivétel a [PSCustomObject]
Windows PowerShell 5.1-ben (ez a PowerShell 6.0-ban van javítva). Nem rendelkezik darabszámtulajdonságsal, ezért ha használni próbálja, kap egy $null
értéket. Azért hívom ezt ide, hogy ne próbálja meg csekk helyett $null
használni.Count
.
A példa Windows PowerShell 5.1-en és PowerShell 6.0-n való futtatása eltérő eredményeket ad.
$value = [PSCustomObject]@{Name='MyObject'}
if ( $value.count -eq 1 )
{
"We have a value"
}
Üres null
Van egy speciális típus $null
, amely másképp viselkedik, mint a többi. Üresnek fogom nevezni$null
, de valójában System.Management.Automation.Internal.AutomationNull. Ez az üres $null
az, amelyet egy függvény vagy szkriptblokk eredményeként kap, amely semmit (üres eredményt) ad vissza.
PS> function Get-Nothing {}
PS> $nothing = Get-Nothing
PS> $null -eq $nothing
True
Ha összehasonlítja a értékkel $null
, egy értéket kap $null
. Ha olyan kiértékelésben használják, ahol szükség van egy értékre, az érték mindig $null
. Ha azonban egy tömbben helyezi el, az üres tömbként lesz kezelve.
PS> $containempty = @( @() )
PS> $containnothing = @($nothing)
PS> $containnull = @($null)
PS> $containempty.count
0
PS> $containnothing.count
0
PS> $containnull.count
1
Egy olyan tömb is lehet, amely egy $null
értéket tartalmaz, és a tömb értéke count
.1
Ha azonban üres eredményt helyez el egy tömbben, akkor az nem számít elemnek. A szám .0
Ha gyűjteményként kezeli az üreset $null
, akkor üres.
Ha üres értéket ad át egy nem erősen beírt függvényparaméternek, a PowerShell alapértelmezés szerint a semmi értékét egy $null
értékre kényszeríti. Ez azt jelenti, hogy a függvényen belül az érték a System.Management.Automation.Internal.AutomationNull típus helyett lesz kezelve.$null
Folyamat
A különbség elsődleges helye a folyamat használata. Az értékeket csövezheti $null
, üres $null
értéket azonban nem.
PS> $null | ForEach-Object{ Write-Output 'NULL Value' }
'NULL Value'
PS> $nothing | ForEach-Object{ Write-Output 'No Value' }
A kódtól függően figyelembe kell vennie a $null
logikát.
Vagy ellenőrizze az elsőt $null
- Null szűrés a folyamaton (
... | Where {$null -ne $_} | ...
) - Kezelés a folyamatfüggvényben
foreach
Az egyik kedvenc funkciója foreach
az, hogy nem számba veszi a $null
gyűjtemény.
foreach ( $node in $null )
{
#skipped
}
Így nem kell ellenőriznem $null
a gyűjteményt, mielőtt enumerálnám. Ha értékgyűjteménysel rendelkezik$null
, akkor is $null
lehet.$node
A foreach így kezdett dolgozni a PowerShell 3.0-val. Ha történetesen egy régebbi verzión dolgozik, akkor ez nem így van. Ez az egyik fontos változás, amelyet érdemes figyelembe venni a 2.0-s kompatibilitású kód visszahordásakor.
Értéktípusok
Technikailag csak referenciatípusok lehetnek $null
. A PowerShell azonban nagyon nagylelkű, és lehetővé teszi, hogy a változók bármilyen típusúak legyenek. Ha úgy dönt, hogy erősen beír egy értéktípust, az nem lehet $null
.
A PowerShell számos típus alapértelmezett értékére konvertálható $null
.
PS> [int]$number = $null
PS> $number
0
PS> [bool]$boolean = $null
PS> $boolean
False
PS> [string]$string = $null
PS> $string -eq ''
True
Vannak olyan típusok, amelyek nem rendelkeznek érvényes konverzióval a következőből $null
: . Ezek a típusok hibát okoznak Cannot convert null to type
.
PS> [datetime]$date = $null
Cannot convert null to type "System.DateTime".
At line:1 char:1
+ [datetime]$date = $null
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
+ FullyQualifiedErrorId : RuntimeException
Függvényparaméterek
A függvényparaméterek erősen beírt értékeinek használata nagyon gyakori. Általában akkor is megtanuljuk definiálni a paraméterek típusait, ha a szkriptekben általában nem definiáljuk más változók típusait. Előfordulhat, hogy már van néhány erősen beírt változó a függvényekben, és nem is veszi észre.
function Do-Something
{
param(
[String] $Value
)
}
Amint beállítja a paraméter string
típusát, az érték soha nem lehet $null
. Gyakran előfordul, hogy ellenőrzi, hogy a $null
felhasználó adott-e értéket, vagy sem.
if ( $null -ne $Value ){...}
$Value
üres sztring ''
, ha nincs megadva érték. Használja inkább az automatikus változót $PSBoundParameters.Value
.
if ( $null -ne $PSBoundParameters.Value ){...}
$PSBoundParameters
csak a függvény meghívásakor megadott paramétereket tartalmazza.
A tulajdonság ellenőrzéséhez a ContainsKey
metódust is használhatja.
if ( $PSBoundParameters.ContainsKey('Value') ){...}
IsNotNullOrEmpty
Ha az érték egy sztring, statikus sztringfüggvény használatával ellenőrizheti, hogy az $null
érték vagy egy üres sztring egyszerre.
if ( -not [string]::IsNullOrEmpty( $value ) ){...}
Gyakran használom ezt, amikor tudom, hogy az értéktípusnak sztringnek kell lennie.
Amikor ellenőrizni $null
Védekező szkriptelő vagyok. Amikor meghívok egy függvényt, és hozzárendelem egy változóhoz, megnézem $null
.
$userList = Get-ADUser kevmar
if ($null -ne $userList){...}
Én sokkal szívesebben használja if
, vagy foreach
több mint használ try/catch
. Ne érts félre, még mindig sokat használok try/catch
. Ha azonban hibaállapotot vagy üres eredményhalmazt tudok tesztelni, engedélyezhetem, hogy a kivételkezelés valódi kivételeket eredményez.
Azt is hajlamosak ellenőrizni $null
, mielőtt indexelek egy értéket, vagy metódusokat hívok meg egy objektumon. Ez a két művelet nem működik egy $null
objektum esetében, ezért fontosnak tartom, hogy először érvényesítsük őket. Már foglalkoztam ezekkel a forgatókönyvekkel korábban ebben a bejegyzésben.
Nincs találati forgatókönyv
Fontos tudni, hogy a különböző függvények és parancsok eltérően kezelik a találatok nélküli forgatókönyvet. Számos PowerShell-parancs az üres $null
és a hibastreamben lévő hibát adja vissza. Mások azonban kivételeket vetnek ki, vagy állapotobjektumot adnak. Továbbra is önön múlik, hogy a használt parancsok hogyan kezelik az eredményeket és a hibaforgatókönyveket.
Inicializálás a $null
Az egyik szokás, amit felvettem, hogy inicializálja az összes változót, mielőtt használnám őket. Ezt más nyelveken is meg kell tennie. A függvény tetején vagy egy foreach ciklus beírása közben definiálom az összes értéket, amelyet használok.
Íme egy forgatókönyv, amelyet szeretném, ha megvizsgálna. Ez egy példa arra a hibára, amit előbb le kellett üldöznem.
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
}
}
}
Az elvárás itt az, hogy Get-Something
egy eredményt vagy egy üres $null
értéket ad vissza. Ha hiba történt, naplózzuk. Ezután ellenőrizzük, hogy van-e érvényes eredmény a feldolgozás előtt.
A kódban elrejtett hiba az, amikor Get-Something
kivételt jelez, és nem rendel hozzá értéket $result
. A hozzárendelés előtt meghiúsul, így még a $result
változóhoz sem rendelünk hozzá$null
. $result
a többi iterációból származó előző érvényeset $result
továbbra is tartalmazza.
Update-Something
többször is végrehajthatja ugyanazon az objektumon ebben a példában.
A foreach hurokon belülre állítottam $result
$null
, mielőtt használnám a probléma megoldásához.
foreach ( $node in 1..6 )
{
$result = $null
try
{
...
Hatókörrel kapcsolatos problémák
Ez segít a hatókörkezelési problémák megoldásában is. Ebben a példában egy ciklusban rendelünk hozzá értékeket $result
újra és újra. Mivel azonban a PowerShell lehetővé teszi, hogy a függvényen kívüli változó értékek kifutódjanak az aktuális függvény hatókörébe, a függvényen belüli inicializálás csökkenti az így bevezethető hibákat.
A függvény nem inicializált változója nem $null
akkor, ha egy szülőhatókörben lévő értékre van beállítva.
A szülőhatókör lehet egy másik függvény, amely meghívja a függvényt, és ugyanazokat a változóneveket használja.
Ha ugyanezt Do-something
a példát venném fel, és eltávolítanám a hurkot, akkor a következő példához hasonló eredményt adnék:
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
}
}
Ha a hívás kivételt jelez Get-Something
, akkor a csekk megkeresi $null
a $result
következőt Invoke-Something
: . A függvényen belüli érték inicializálása csökkenti ezt a problémát.
A változók elnevezése nehéz, és gyakran előfordul, hogy egy szerző ugyanazt a változónevet használja több függvényben. Tudom, hogy mindig ezt használom$node
$result
$data
. Így nagyon könnyű lenne, ha a különböző hatókörök értékei olyan helyeken jelennének meg, ahol nem kellene.
Kimenet átirányítása $null
Az egész cikk értékeiről $null
beszéltem, de a témakör nem teljes, ha nem említettem a kimenet $null
átirányítását. Vannak olyan parancsok, amelyek le szeretné tiltani az adatokat vagy objektumokat. A kimenet átirányítása erre $null
.
Out-Null
A Out-Null parancs a folyamatadatok $null
átirányításának beépített módja.
New-Item -Type Directory -Path $path | Out-Null
Hozzárendelés $null
A parancsok $null
eredményeit ugyanahhoz a hatáshoz rendelheti hozzá, mint a használatával Out-Null
.
$null = New-Item -Type Directory -Path $path
Mivel $null
ez egy állandó érték, soha nem írhatja felül. Nem tetszik, ahogy a kódban néz ki, de gyakran gyorsabban teljesít, mint Out-Null
.
Átirányítás $null
Az átirányítási operátorral kimenetet is küldhet a rendszernek $null
.
New-Item -Type Directory -Path $path > $null
Ha olyan parancssori végrehajtható fájlokkal foglalkozik, amelyek a különböző streameken futnak. Az összes kimeneti streamet $null
a következőképpen irányíthatja át:
git status *> $null
Összegzés
Sokat foglalkoztam ezzel, és tudom, hogy ez a cikk töredezettebb, mint a legtöbb mély merülésem. Ennek az az oka, hogy $null
az értékek számos különböző helyen előugranak a PowerShellben, és az összes árnyalat a megtalálás helyére jellemző. Remélem, hogy elsétálsz ettől egy jobb megértéssel $null
és a homályosabb forgatókönyvek tudatosításával.
Visszajelzés
https://aka.ms/ContentUserFeedback.
Hamarosan elérhető: 2024-ben fokozatosan kivezetjük a GitHub-problémákat a tartalom visszajelzési mechanizmusaként, és lecseréljük egy új visszajelzési rendszerre. További információ:Visszajelzés küldése és megtekintése a következőhöz: