[玩转系统] 关于 $null 你想知道的一切
作者:精品下载站 日期:2024-12-14 03:04:07 浏览:16 分类:玩电脑
关于 $null 你想知道的一切
PowerShell $null
通常看起来很简单,但它有很多细微差别。让我们仔细看看 $null
,这样您就知道当意外遇到 $null
值时会发生什么。
笔记
本文的原始版本出现在@KevinMarquette 撰写的博客上。 PowerShell 团队感谢 Kevin 与我们分享这些内容。请查看他的博客:PowerShellExplained.com。
什么是NULL?
您可以将 NULL 视为未知值或空值。变量在您为其分配值或对象之前一直为 NULL。这可能很重要,因为有些命令需要一个值,如果该值为 NULL,则会生成错误。
PowerShell $null
$null
是 PowerShell 中的一个自动变量,用于表示 NULL。您可以将其分配给变量,在比较中使用它,并将其用作集合中 NULL 的占位符。
PowerShell 将 $null
视为值为 NULL 的对象。如果您来自其他语言,这可能与您所期望的不同。
$null 的示例
每当您尝试使用尚未初始化的变量时,该值为 $null
。这是 $null
值潜入代码的最常见方式之一。
PS> $null -eq $undefinedVariable
True
如果您碰巧输错了变量名称,PowerShell 会将其视为不同的变量,并且值为 $null
。
查找 $null
值的另一种方法是当它们来自不给您任何结果的其他命令时。
PS> function Get-Nothing {}
PS> $value = Get-Nothing
PS> $null -eq $value
True
$null 的影响
$null
值对您的代码的影响不同,具体取决于它们出现的位置。
在字符串中
如果在字符串中使用 $null
,则它是空白值(或空字符串)。
PS> $value = $null
PS> Write-Output "The value is $value"
The value is
这是我喜欢在日志消息中使用变量时将变量放在括号内的原因之一。当变量值位于字符串末尾时,识别变量值的边缘更为重要。
PS> $value = $null
PS> Write-Output "The value is [$value]"
The value is []
这使得空字符串和 $null
值很容易被发现。
在数值方程中
当在数值方程中使用 $null
值时,如果没有给出错误,则结果无效。有时,$null
的计算结果为 0
,有时它会得出整个结果 $null
。下面是一个乘法示例,根据值的顺序给出 0 或 $null
。
PS> $null * 5
PS> $null -eq ( $null * 5 )
True
PS> 5 * $null
0
PS> $null -eq ( 5 * $null )
False
代替集合
集合允许您使用索引来访问值。如果您尝试对实际上为 null
的集合建立索引,则会收到此错误:无法对 null 数组建立索引
。
PS> $value = $null
PS> $value[10]
Cannot index into a null array.
At line:1 char:1
+ $value[10]
+ ~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : NullArray
如果您有一个集合,但尝试访问不在该集合中的元素,您将得到 $null
结果。
$array = @( 'one','two','three' )
$null -eq $array[100]
True
代替物体
如果您尝试访问没有指定属性的对象的属性或子属性,您将得到一个 $null
值,就像访问未定义的变量一样。在这种情况下,变量是 $null
还是实际对象并不重要。
PS> $null -eq $undefined.some.fake.property
True
PS> $date = Get-Date
PS> $null -eq $date.some.fake.property
True
空值表达式上的方法
在 $null
对象上调用方法会引发 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
每当我看到短语 You can not call a method on a null-valued expression
时,我首先要查找的是在没有先检查变量 $的情况下调用变量方法的位置空
。
检查 $null
您可能已经注意到,在示例中检查 $null
时,我总是将 $null
放在左侧。这是有意为之,并被视为 PowerShell 最佳实践。在某些情况下,将其放在右侧不会给您带来预期的结果。
看下一个例子并尝试预测结果:
if ( $value -eq $null )
{
'The array is $null'
}
if ( $value -ne $null )
{
'The array is not $null'
}
如果我没有定义$value
,第一个值的计算结果为$true
,我们的消息是The array is $null
。这里的陷阱是可以创建一个 $value
来允许它们都为 $false
$value = @( $null )
在本例中,$value
是一个包含 $null
的数组。 -eq
检查数组中的每个值并返回匹配的 $null
。其计算结果为$false
。 -ne
返回与 $null
不匹配的所有内容,在这种情况下没有结果(这也计算为 $false
)。尽管看起来其中之一应该是,但两者都不是 $true
。
我们不仅可以创建一个使它们都计算为 $false
的值,还可以创建一个使它们都计算为 $true
的值。 Mathias Jessen (@IISResetMe) 有一篇很好的文章深入探讨了这种情况。
PSScriptAnalyzer 和 VSCode
PSScriptAnalyzer 模块有一个名为 PSPossibleIn CorrectComparisonWithNull
的规则来检查此问题。
PS> Invoke-ScriptAnalyzer ./myscript.ps1
RuleName Message
-------- -------
PSPossibleIncorrectComparisonWithNull $null should be on the left side of equality comparisons.
由于 VS Code 也使用 PSScriptAnalyser 规则,因此它还会突出显示或将此识别为脚本中的问题。
简单的 if 检查
人们检查非 $null 值的常见方法是使用简单的 if()
语句而不进行比较。
if ( $value )
{
Do-Something
}
如果值为 $null
,则计算结果为 $false
。这很容易阅读,但要小心它正在寻找的正是您期望它寻找的内容。我将这行代码读为:
如果$value
有一个值。
但这还不是故事的全部。这句话实际上是在说:
如果 $value
不是 $null
或 0
或 $false
或者空字符串或空数组。
这是该声明的更完整示例。
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
}
只要您记住其他值也算作 $false
而不仅仅是变量有值,使用基本的 if
检查就完全没问题。
前几天重构一些代码时遇到了这个问题。它有一个像这样的基本属性检查。
if ( $object.property )
{
$object.property = $value
}
我只想在对象属性存在时为其赋值。在大多数情况下,原始对象的值在 if
语句中计算结果为 $true
。但我遇到了一个问题,即该值有时无法设置。我调试了代码,发现该对象具有该属性,但它是一个空字符串值。这阻止了它用以前的逻辑进行更新。因此,我添加了适当的 $null
检查,一切正常。
if ( $null -ne $object.property )
{
$object.property = $value
}
像这样的小错误很难发现,因此我需要积极检查 $null
的值。
$null.Count
如果您尝试访问 $null
值的属性,则该属性也是 $null
。 count
属性是此规则的例外。
PS> $value = $null
PS> $value.count
0
当您有 $null
值时,count
为 0
。此特殊属性是由 PowerShell 添加的。
[PS自定义对象] 计数
PowerShell 中的几乎所有对象都具有该 count 属性。一个重要的例外是 Windows PowerShell 5.1 中的 [PSCustomObject]
(这一问题在 PowerShell 6.0 中已修复)。它没有 count 属性,因此如果您尝试使用它,您会得到一个 $null
值。我在这里指出这一点,这样您就不会尝试使用 .Count
代替 $null
检查。
在 Windows PowerShell 5.1 和 PowerShell 6.0 上运行此示例会产生不同的结果。
$value = [PSCustomObject]@{Name='MyObject'}
if ( $value.count -eq 1 )
{
"We have a value"
}
可枚举空值
有一种特殊类型的 $null
其行为与其他类型不同。我将其称为可枚举 null,但它实际上是一个 System.Management.Automation.Internal.AutomationNull。这个可枚举 null 是作为不返回任何内容的函数或脚本块的结果而获得的值(空结果)。
PS> function Get-Nothing {}
PS> $nothing = Get-Nothing
PS> $null -eq $nothing
True
如果将其与 $null
进行比较,您会得到一个 $null
值。当用于需要值的评估时,该值始终为 $null
。但如果将其放入数组中,则将其视为与空数组相同。
PS> $containempty = @( @() )
PS> $containnothing = @($nothing)
PS> $containnull = @($null)
PS> $containempty.count
0
PS> $containnothing.count
0
PS> $containnull.count
1
您可以拥有一个包含一个 $null
值且其 count
为 1
的数组。但是,如果您在数组中放置一个空数组,那么它不会被算作一个项目。计数为0
。
如果将可枚举 null 视为集合,那么它就是空的。
如果将可枚举 null 传递给非强类型的函数参数,PowerShell 默认情况下会将可枚举 null 强制转换为 $null
值。这意味着在函数内部,该值被视为 $null
而不是 System.Management.Automation.Internal.AutomationNull 类型。
管道
您看到差异的主要地方是使用管道时。您可以通过管道传递 $null
值,但不能传递可枚举的 null 值。
PS> $null | ForEach-Object{ Write-Output 'NULL Value' }
'NULL Value'
PS> $nothing | ForEach-Object{ Write-Output 'No Value' }
根据您的代码,您应该在逻辑中考虑 $null
。
首先检查 $null
- 过滤掉管道上的 null (
... | 其中 {$null -ne $_} | ...
) - 在管道函数中处理
foreach
我最喜欢的 foreach
功能之一是它不会枚举 $null
集合。
foreach ( $node in $null )
{
#skipped
}
这使我不必在枚举集合之前 $null
检查集合。如果您有 $null
值的集合,则 $node
仍然可以是 $null
。
foreach 在 PowerShell 3.0 中开始以这种方式工作。如果您碰巧使用的是旧版本,则情况并非如此。这是向后移植代码以实现 2.0 兼容性时需要注意的重要更改之一。
值类型
从技术上讲,只有引用类型可以是 $null
。但 PowerShell 非常慷慨,允许变量是任何类型。如果您决定强类型化值类型,则它不能是 $null
。 PowerShell 将 $null
转换为许多类型的默认值。
PS> [int]$number = $null
PS> $number
0
PS> [bool]$boolean = $null
PS> $boolean
False
PS> [string]$string = $null
PS> $string -eq ''
True
有些类型没有从 $null
进行有效的转换。这些类型会生成无法将 null 转换为类型
错误。
PS> [datetime]$date = $null
Cannot convert null to type "System.DateTime".
At line:1 char:1
+ [datetime]$date = $null
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
+ FullyQualifiedErrorId : RuntimeException
功能参数
在函数参数中使用强类型值是很常见的。即使我们倾向于不定义脚本中其他变量的类型,我们通常也会学习定义参数的类型。您的函数中可能已经有一些强类型变量,但您甚至没有意识到。
function Do-Something
{
param(
[String] $Value
)
}
一旦将参数类型设置为 string
,该值就永远不会是 $null
。通常检查值是否为 $null
以查看用户是否提供了值。
if ( $null -ne $Value ){...}
当未提供值时,$Value
是一个空字符串 ''
。请改用自动变量 $PSBoundParameters.Value
。
if ( $null -ne $PSBoundParameters.Value ){...}
$PSBoundParameters
仅包含调用函数时指定的参数。您还可以使用 ContainsKey
方法来检查该属性。
if ( $PSBoundParameters.ContainsKey('Value') ){...}
不为空或为空
如果该值为字符串,则可以使用静态字符串函数同时检查该值为 $null
或空字符串。
if ( -not [string]::IsNullOrEmpty( $value ) ){...}
当我知道值类型应该是字符串时,我发现自己经常使用它。
当我 $null 检查时
我是一名防守型脚本编写者。每当我调用函数并将其分配给变量时,我都会检查它是否有 $null
。
$userList = Get-ADUser kevmar
if ($null -ne $userList){...}
与使用 try/catch
相比,我更喜欢使用 if
或 foreach
。不要误会我的意思,我仍然经常使用 try/catch
。但是,如果我可以测试错误条件或空结果集,我就可以允许我的异常处理针对真正的异常。
我还倾向于在索引值或调用对象的方法之前检查 $null
。对于 $null
对象,这两个操作会失败,因此我发现首先验证它们很重要。我已经在本文前面介绍了这些场景。
无结果场景
重要的是要知道不同的函数和命令以不同的方式处理无结果场景。许多 PowerShell 命令在错误流中返回可枚举的 null 和错误。但其他人会抛出异常或给你一个状态对象。您仍然需要了解您使用的命令如何处理无结果和错误情况。
初始化为$null
我养成的一个习惯是在使用所有变量之前初始化它们。您需要使用其他语言执行此操作。在函数的顶部或当我进入 foreach 循环时,我定义了我正在使用的所有值。
我希望您仔细观察以下场景。这是我之前必须追查的错误的一个例子。
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
}
}
}
这里的期望是 Get-Something
返回结果或可枚举的 null。如果出现错误,我们会记录下来。然后我们检查以确保在处理之前获得有效的结果。
此代码中隐藏的错误是 Get-Something
引发异常并且不为 $result
赋值。它在赋值之前失败,因此我们甚至不将 $null
分配给 $result
变量。 $result
仍包含来自其他迭代的先前有效 $result
。在此示例中,Update-Something
对同一对象执行多次。
在使用 foreach 循环来缓解此问题之前,我将 $result
设置为 $null
。
foreach ( $node in 1..6 )
{
$result = $null
try
{
...
范围问题
这也有助于缓解范围问题。在该示例中,我们在循环中一遍又一遍地为 $result
赋值。但由于 PowerShell 允许函数外部的变量值渗入当前函数的范围,因此在函数内部初始化它们可以减少通过这种方式引入的错误。
如果函数中未初始化的变量设置为父作用域中的值,则该变量不是 $null
。父作用域可以是调用您的函数并使用相同变量名称的另一个函数。
如果我采用相同的 Do-something
示例并删除循环,我最终会得到如下示例所示的结果:
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
}
}
如果对 Get-Something
的调用引发异常,那么我的 $null
检查会从 Invoke-Something
找到 $result
代码>.初始化函数内的值可以缓解这个问题。
命名变量很困难,作者在多个函数中使用相同的变量名是很常见的。我知道我一直使用 $node
、$result
、$data
。因此,来自不同范围的值很容易出现在不应该出现的地方。
将输出重定向到 $null
我在整篇文章中一直在讨论 $null
值,但如果我没有提到将输出重定向到 $null
,那么该主题就不完整。有时,您的命令会输出您想要抑制的信息或对象。将输出重定向到 $null
即可做到这一点。
Out-Null
Out-Null 命令是将管道数据重定向到 $null
的内置方法。
New-Item -Type Directory -Path $path | Out-Null
分配给$null
您可以将命令的结果分配给 $null
,以获得与使用 Out-Null
相同的效果。
$null = New-Item -Type Directory -Path $path
由于 $null
是一个常量值,因此您永远无法覆盖它。我不喜欢它在代码中的样子,但它通常比 Out-Null
执行得更快。
重定向到 $null
您还可以使用重定向运算符将输出发送到 $null
。
New-Item -Type Directory -Path $path > $null
如果您正在处理在不同流上输出的命令行可执行文件。您可以将所有输出流重定向到 $null
,如下所示:
git status *> $null
概括
我在这篇文章上讨论了很多内容,我知道这篇文章比我的大部分深入研究都更加零散。这是因为 $null
值可能会在 PowerShell 中的许多不同位置弹出,并且所有细微差别都特定于您找到它的位置。我希望您能够更好地理解 $null
并了解您可能遇到的更晦涩的场景。
猜你还喜欢
- 03-30 [玩转系统] 如何用批处理实现关机,注销,重启和锁定计算机
- 02-14 [系统故障] Win10下报错:该文件没有与之关联的应用来执行该操作
- 01-07 [系统问题] Win10--解决锁屏后会断网的问题
- 01-02 [系统技巧] Windows系统如何关闭防火墙保姆式教程,超详细
- 12-15 [玩转系统] 如何在 Windows 10 和 11 上允许多个 RDP 会话
- 12-15 [玩转系统] 查找 Exchange/Microsoft 365 中不活动(未使用)的通讯组列表
- 12-15 [玩转系统] 如何在 Windows 上安装远程服务器管理工具 (RSAT)
- 12-15 [玩转系统] 如何在 Windows 上重置组策略设置
- 12-15 [玩转系统] 如何获取计算机上的本地管理员列表?
- 12-15 [玩转系统] 在 Visual Studio Code 中连接到 MS SQL Server 数据库
- 12-15 [玩转系统] 如何降级 Windows Server 版本或许可证
- 12-15 [玩转系统] 如何允许非管理员用户在 Windows 中启动/停止服务
取消回复欢迎 你 发表评论:
- 精品推荐!
-
- 最新文章
- 热门文章
- 热评文章
[影视] 黑道中人 Alto Knights(2025)剧情 犯罪 历史 电影
[古装剧] [七侠五义][全75集][WEB-MP4/76G][国语无字][1080P][焦恩俊经典]
[实用软件] 虚拟手机号 电话 验证码 注册
[电视剧] 安眠书店/你 第五季 You Season 5 (2025) 【全10集】
[电视剧] 棋士(2025) 4K 1080P【全22集】悬疑 犯罪 王宝强 陈明昊
[软件合集] 25年6月5日 精选软件22个
[软件合集] 25年6月4日 精选软件36个
[短剧] 2025年06月04日 精选+付费短剧推荐33部
[短剧] 2025年06月03日 精选+付费短剧推荐25部
[软件合集] 25年6月3日 精选软件44个
[剧集] [央视][笑傲江湖][2001][DVD-RMVB][高清][40集全]李亚鹏、许晴、苗乙乙
[电视剧] 欢乐颂.5部全 (2016-2024)
[电视剧] [突围] [45集全] [WEB-MP4/每集1.5GB] [国语/内嵌中文字幕] [4K-2160P] [无水印]
[影视] 【稀有资源】香港老片 艺坛照妖镜之96应召名册 (1996)
[剧集] 神经风云(2023)(完结).4K
[剧集] [BT] [TVB] [黑夜彩虹(2003)] [全21集] [粤语中字] [TV-RMVB]
[实用软件] 虚拟手机号 电话 验证码 注册
[资源] B站充电视频合集,包含多位重量级up主,全是大佬真金白银买来的~【99GB】
[影视] 内地绝版高清录像带 [mpg]
[书籍] 古今奇书禁书三教九流资料大合集 猎奇必备珍藏资源PDF版 1.14G
[电视剧] [突围] [45集全] [WEB-MP4/每集1.5GB] [国语/内嵌中文字幕] [4K-2160P] [无水印]
[剧集] [央视][笑傲江湖][2001][DVD-RMVB][高清][40集全]李亚鹏、许晴、苗乙乙
[电影] 美国队长4 4K原盘REMUX 杜比视界 内封简繁英双语字幕 49G
[电影] 死神来了(1-6)大合集!
[软件合集] 25年05月13日 精选软件16个
[精品软件] 25年05月15日 精选软件18个
[绝版资源] 南与北 第1-2季 合集 North and South (1985) /美国/豆瓣: 8.8[1080P][中文字幕]
[软件] 25年05月14日 精选软件57个
[短剧] 2025年05月14日 精选+付费短剧推荐39部
[短剧] 2025年05月15日 精选+付费短剧推荐36部
- 最新评论
-
- 热门tag