Как удалить элемент из массива в PowerShell? - PullRequest
6 голосов
/ 26 февраля 2010

Я использую 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 возвращает тип System.Array. Поэтому я получаю эту ошибку при попытке использовать метод Remove:

Method invocation failed because [System.Object[]] doesn't contain a method named 'Remove'.

Что я хотел бы сделать, так это конвертировать $ filesToDelete в ArrayList, а затем удалять элементы с помощью ArrayList.Remove. Это хорошая идея, или я должен каким-то образом напрямую манипулировать $ filesToDelete как System.Array?

Спасибо

Ответы [ 3 ]

9 голосов
/ 26 февраля 2010

Лучший способ сделать это - использовать 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 они неизменны, их нельзя изменить, но очень легко создать новый (операторы, подобные += для массивов, фактически создают новый массив и возвращают его).

3 голосов
/ 26 февраля 2010

Я согласен с Ричардом, что 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
0 голосов
/ 20 августа 2015

Это древний. Но я написал это некоторое время назад, чтобы добавлять и удалять из списков powershell с помощью рекурсии. Он использует способность powershell для выполнения многократного назначения . То есть вы можете сделать $a,$b,$c=@('a','b','c'), чтобы назначить b и c их переменным. Выполнение $a,$b=@('a','b','c') назначает 'a' на $a и @('b','c') на $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 )
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...