警告:Powershell新手,术语/代码可能是不正确的
假设我有一个Powershell数组,其中包含来自Invoke-Sqlcmd的数据,例如10000";行";每个具有六个(Col1-Col6(列。说我想找到每一排都有一个空的Col5。现在我在做
foreach ($row in $sqlimport.col1)
{ $col5data = $sqlimport.Where({$_.col1 -eq $row}) | Select-Object -ExpandProperty Col5
if ( '' -eq $col5data ) {$col5data+1} else {} $col5data
返回1,它应该在我的测试中返回。代码似乎错误且速度缓慢。跑完全程需要几分钟。当类似的东西
$sqlimport.Where({$_.col5 -eq 'somedatathatisthere'})
耗时毫秒
然而,
$sqlimport.Where({$_.col5 -eq ''})
返回空白
($sqlimport.Where({$_.col5 -eq ''})).Count
返回0
现在,您要求PowerShell创建一个由列col1
中的所有值组成的数组,然后在每次迭代中再次搜索整个数组以查找相应的col5
值。这完全没有必要。
只需在阵列本身上循环:
foreach($row in $sqlimport){
if($row.Col5 -like ''){
Write-Host "Col5 is empty in row with id $($row.Col1)"
}
}
这只会在整个数组上迭代一次。
Mathias的回答很好地解释了第一次尝试效率低下的问题,并提供了一个最终性能最佳的解决方案,因为使用了(单个(foreach
语句(而不是慢得多的ForEach-Object
cmdlet(。
但是,使用(单个(.Where()
数组方法调用(或相关的.ForEach()
方法(的解决方案:
- 仅稍慢[1]
- 同时更简洁并且可以说在概念上更优雅
这就是你在$sqlimport.Where({ $_.col5 -eq '' })
上尝试的,根据你的反馈,它只需要一个小的调整就可以工作:
- 使用
-like ''
而不是-eq ''
,这是测试空字符串(''
(和测试$null
值(也在Mathias的答案中使用(的一个有点模糊的[2]快捷方式,本质上,它相当于的.NET[string]::IsNullOrEmpty()
方法
# -like matches both '' and $null
$sqlimport.Where({ $_.col5 -like '' })
注:
如果您希望仅测试
$null
值,请使用以下命令;注意$null
是如何放置在LHS上的,这对于鲁棒比较通常是可取的[3]:$sqlimport.Where({ $null -eq $_.col5 })
- 顺便说一句:GitHub问题#10656建议为
$null
引入一个类似-is $null
的简化测试;不幸的是,相关的PR已被放弃
- 顺便说一句:GitHub问题#10656建议为
顺便说一句:
[string]
-类型受限的PowerShell变量从不存储$null
值:[string] $str = $null
导致$str
包含''
,而不是$null
。但是,未在PowerShell代码中填充的[string]
类型的属性值可以包含$null
值,就像您的情况一样。- 若要在PowerShell代码中将真正的
$null
值传递给string
类型的.NET API,必须使用特殊单例(直接传递$null
将再次导致''):
[NullString]::value` - 有关背景信息,请参阅此答案
- 若要在PowerShell代码中将真正的
[1]有关PowerShell各种枚举(迭代(功能的性能比较,请参阅此答案的底部
[2]-like
运算符的真正目的是执行通配符表达式匹配。快捷方式依赖于-like
-仅对(非null(字符串进行操作-自动将非字符串操作数转换为字符串,在$null
的情况下,这会导致转换为''
(空字符串TR
[3]为了可靠地测试$null
,将其放置在-eq
/-ne
操作的LHS上;例如$null -eq $var
。如果将$null
放置在RHS-$var -eq $null
-上,而$var
恰好是集合(例如数组(,则返回值为匹配元素的数组,即$var
中那些元素的数组,其值为$null
,这是一个不同的操作-请参阅about_Comparison_Operators