Как удалить элемент из массива в PowerShell?
Я использую Powershell 1.0 для удаления элемента из массива. Вот мой скрипт:
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!"}
}
}
Я понимаю, что Get-ChildItem в powershell возвращает систему.Тип массива. Поэтому я получаю эту ошибку при попытке использовать метод remove:
Method invocation failed because [System.Object[]] doesn't contain a method named 'Remove'.
что я хотел бы сделать, это преобразовать $filesToDelete в ArrayList, а затем удалить элементы с помощью ArrayList.Удалять. Это хорошая идея или я должен напрямую манипулировать $filesToDelete как системой.Массив в некоторых способ?
спасибо
3 ответов
лучший способ сделать это-использовать Where-Object
для выполнения фильтрации и использования возвращаемого массива.
вы также можете использовать @splat
для передачи нескольких параметров команде (new in V2). Если вы не можете обновить (и вы должны, если это вообще возможно, просто собрать выходные данные из Get-ChildItems (только повторяя этот командлет) и выполнить всю фильтрацию в общем коде).
рабочая часть вашего скрипта становится:
$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 делать множественные задание . То есть, вы можете сделать $a,$b,$c=@('a','b','c')
назначить B и c своим переменным. Делать $a,$b=@('a','b','c')
назначает 'a'
до $a
и @('b','c')
to $b
.
сначала по значению элемента. Он удалит первое появление.
function Remove-ItemFromList ($Item,[array]$List(throw"the item $item was not in the list"),[array]$chckd_list=@())
{
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]$chckd_list=@(),[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 )
}
}