PowerShell中Foreach+If无法正确移除数组元素的问题排查
PowerShell数组移除指定元素问题解答
我是PowerShell完全新手,希望能得到易懂的解答。我尝试编写一段代码,当数组元素包含特定内容('Apple'和'Banana')时,将该元素从数组中移除。我编写了如下测试代码,第一次迭代能正确移除元素,但后续出现异常,请问问题出在哪里?
测试代码
$Text = @("Apple and Orange", "Pear and Grape", "Peach and Mango", "Avocado and Banana") $x = 0 $NotItem = "Banana" $NoSales = "Apple" cls foreach ($element in $Text) { # Remove elemets from array that don't contain purchasable items if ($element -contains $NotItem -or $element -match $NoSales) { $Text[$x] = $null $Next = $Text[$x] Write-Host "Condition Met. $element, Step $x, `n`n` Current Array: $Text`n`n` Next Item: $Next`n`n" } # If neither applies, move on else { $x = $x + 1 $Next = $Text[$x] Write-Host "Condition Not Met. $element, Step $x, `n`n` Current Array: $Text`n`n` Next Item: $Next`n`n" } }
代码输出
Condition Met. Apple and Orange, Step 0, Current Array: Pear and Grape Peach and Mango Avocado and Banana Next Item: Condition Not Met. Pear and Grape, Step 1, Current Array: Pear and Grape Peach and Mango Avocado and Banana Next Item: Pear and Grape Condition Not Met. Peach and Mango, Step 2, Current Array: Pear and Grape Peach and Mango Avocado and Banana Next Item: Peach and Mango Condition Not Met. Avocado and Banana, Step 3, Current Array: Pear and Grape Peach and Mango Avocado and Banana Next Item: Avocado and Banana
问题分析
-contains运算符使用错误:-contains是用来检查数组是否包含某个元素的,而你这里的$element是字符串,不是数组。要判断字符串中是否包含子串,应该用$element -like "*$NotItem*"(通配符匹配)或者$element.Contains($NotItem)(字符串方法),你当前的$element -contains $NotItem永远返回false,所以只有-match $NoSales触发了第一个元素的判断。- 在
foreach循环中修改原数组逻辑错误:PowerShell的foreach循环是基于原数组的快照创建的,修改原数组不会影响循环的迭代次数和遍历的元素。而且你把元素设为$null并不是真正移除元素,数组的长度还是原来的4,只是第一个元素变成了$null,输出时$null会被忽略,看起来像是移除了,但实际上数组里还存在这个空元素。 - 手动维护索引
$x逻辑混乱:当你把第一个元素设为$null后,后续的$x递增逻辑会导致索引错位,比如最后一个元素Avocado and Banana本来应该被匹配到,但因为-contains用错了没触发,加上$x的错误递增,导致它被当成符合保留条件的元素处理。
正确实现方法
PowerShell中过滤数组最简洁的方式是用Where-Object,直接筛选出不需要移除的元素,生成新数组:
$Text = @("Apple and Orange", "Pear and Grape", "Peach and Mango", "Avocado and Banana") $NotItem = "Banana" $NoSales = "Apple" # 筛选出既不包含Apple也不包含Banana的元素 $filteredText = $Text | Where-Object { $_ -notlike "*$NoSales*" -and $_ -notlike "*$NotItem*" } # 输出结果 $filteredText
运行这段代码会得到:
Pear and Grape Peach and Mango
如果你一定要用循环的方式实现,应该遍历原数组,把符合保留条件的元素添加到新数组中,而不是修改原数组:
$Text = @("Apple and Orange", "Pear and Grape", "Peach and Mango", "Avocado and Banana") $NotItem = "Banana" $NoSales = "Apple" $filteredText = @() foreach ($element in $Text) { # 如果元素既不包含Apple也不包含Banana,就添加到新数组 if ($element -notlike "*$NoSales*" -and $element -notlike "*$NotItem*") { $filteredText += $element } } $filteredText
内容的提问来源于stack exchange,提问作者alfus
相关产品推荐
相关产品推荐

