如何从PowerShell中的数组中删除项目?
我使用Powershell 1.0从数组中删除项目。这是我的脚本:如何从PowerShell中的数组中删除项目?
param (
[string]$backupDir = $(throw "Please supply the directory to housekeep"),
[int]$maxAge = 30,
[switch]$NoRecurse,
[switch]$KeepDirectories
)
$days = $maxAge * -1
# do not delete directories with these values in the path
$exclusionList = Get-Content HousekeepBackupsExclusions.txt
if ($NoRecurse)
{
$filesToDelete = Get-ChildItem $backupDir | where-object {$_.PsIsContainer -ne $true -and $_.LastWriteTime -lt $(Get-Date).AddDays($days)}
}
else
{
$filesToDelete = Get-ChildItem $backupDir -Recurse | where-object {$_.PsIsContainer -ne $true -and $_.LastWriteTime -lt $(Get-Date).AddDays($days)}
}
foreach ($file in $filesToDelete)
{
# remove the file from the deleted list if it's an exclusion
foreach ($exclusion in $exclusionList)
{
"Testing to see if $exclusion is in " + $file.FullName
if ($file.FullName.Contains($exclusion)) {$filesToDelete.Remove($file); "FOUND ONE!"}
}
}
我意识到,PowerShell中的Get-ChildItem返回一个System.Array类型。
Method invocation failed because [System.Object[]] doesn't contain a method named 'Remove'.
我想要做的是$ filesToDelete转换到一个ArrayList,然后用ArrayList.Remove删除项目:尝试使用Remove方法时,因此,我得到这个错误。这是一个好主意,还是应该以某种方式直接操作$ filesToDelete作为System.Array?
感谢
做到这一点,最好的方法是使用Where-Object
进行过滤,并使用返回的数组。
您也可以使用@splat
将多个参数传递给一个命令(V2中的新增功能)。如果你不能升级(并且你应该尽可能的话,那么就从Get-ChildItems收集输出(只重复一个CmdLet),然后用通用代码进行所有过滤)。
脚本的工作部分变为:
$moreArgs = @{}
if (-not $NoRecurse) {
$moreArgs["Recurse"] = $true
}
$filesToDelete = Get-ChildItem $BackupDir @moreArgs |
where-object {-not $_.PsIsContainer -and
$_.LastWriteTime -lt $(Get-Date).AddDays($days) -and
-not $_.FullName.Contains($exclusion)}
在PSH数组是不可变的,你不能修改,但它很容易地创建一个新的(像+=
对数组运营商实际上是创建一个新的数组并返回)。
我同意理查德认为应该在这里使用Where-Object
。但是,阅读起来很困难。 我建议什么:
# get $filesToDelete and #exclusionList. In V2 use splatting as proposed by Richard.
$res = $filesToDelete | % {
$file = $_
$isExcluded = ($exclusionList | % { $file.FullName.Contains($_) })
if (!$isExcluded) {
$file
}
}
#the files are in $res
还要注意,一般是不可能遍历集合,并改变它。你会得到一个例外。
$a = New-Object System.Collections.ArrayList
$a.AddRange((1,2,3))
foreach($item in $a) { $a.Add($item*$item) }
An error occurred while enumerating through a collection:
At line:1 char:8
+ foreach <<<< ($item in $a) { $a.Add($item*$item) }
+ CategoryInfo : InvalidOperation: (System.Collecti...numeratorSimple:ArrayListEnumeratorSimple) [], RuntimeException
+ FullyQualifiedErrorId : BadEnumeration
这是古老的。但是,我前一段时间写了这些,使用递归从powershell列表中添加和删除。它利用powershell的能力来做multiple assignment。也就是说,你可以做$a,$b,[email protected]('a','b','c')
来给它们的变量分配一个b和c。做$a,[email protected]('a','b','c')
分配'a'
到$a
和@('b','c')
到$b
。
首先是按项目值。它会删除第一个事件。
function Remove-ItemFromList ($Item,[array]$List(throw"the item $item was not in the list"),[array][email protected]())
{
if ($list.length -lt 1) { throw "the item $item was not in the list" }
$check_item,$temp_list=$list
if ($check_item -eq $item)
{
$chckd_list+=$temp_list
return $chckd_list
}
else
{
$chckd_list+=$check_item
return (Remove-ItemFromList -item $item -chckd_list $chckd_list -list $temp_list)
}
}
这一个由索引移除。你可以通过在初始调用中传递一个值来计算好坏。
function Remove-IndexFromList ([int]$Index,[array]$List,[array][email protected](),[int]$count=0)
{
if (($list.length+$count-1) -lt $index)
{ throw "the index is out of range" }
$check_item,$temp_list=$list
if ($count -eq $index)
{
$chckd_list+=$temp_list
return $chckd_list
}
else
{
$chckd_list+=$check_item
return (Remove-IndexFromList -count ($count + 1) -index $index -chckd_list $chckd_list -list $temp_list)
}
}
(一个错字'PSIsContainere')是的,我更喜欢'Where-Object'。但是在这个问题中有两个循环 - 内部通过'$ exclusionList',所以条件应该是'-not $($ f = $ _。Fullname; $ exclusionList |?{$ f.Contains($ _ )})' – stej 2010-02-26 11:47:56
感谢理查德 - 我可以使用字符串数组作$排除。如果仔细观察代码,您会看到我必须为每个排除项都调用get-childitem。如果我有很多排除,这将不会很好。 – 2010-02-26 11:48:47
@stej:将更正 – Richard 2010-02-26 14:41:31