2010-02-26 71 views
5

Estoy usando Powershell 1.0 para eliminar un elemento de una matriz. Aquí está mi script:¿Cómo eliminar un elemento de una matriz en 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!"} 
    } 
} 

Soy consciente de que Get-ChildItem en PowerShell devuelve un tipo de System.array. Por lo tanto, me sale este error al intentar utilizar el método Remove:

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

Lo que me gustaría hacer es convertir $ filesToDelete a un ArrayList y luego eliminar elementos usando ArrayList.Remove. ¿Es esta una buena idea o debería manipular directamente $ filesToDelete como System.Array de alguna manera?

Gracias

Respuesta

8

La mejor manera de hacer esto es utilizar Where-Object realizar el filtrado y el uso de la matriz devuelta.

También puede utilizar @splat a pasar varios parámetros a un comando (nuevo en V2). Si no puede actualizar (y debe hacerlo si es posible, simplemente recopile la salida de Get-ChildItems (solo repite ese CmdLet) y haga todo el filtrado en código común).

La parte operante de la secuencia de comandos se convierte en:

$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)} 

En matrices PSH son inmutables, no se puede modificar, pero que sea muy fácil crear una nueva (operadores como += en matrices en realidad crean una nueva matriz y devolver eso).

+1

(un error 'PSIsContainere') Sí, preferiría' Where-Object' también. Sin embargo, en la cuestión hay dos bucles - el interior pasa por '$ exclusionList' lo que la condición probablemente debería ser algo como' -no $ ($ f = $ _ Nombre completo; $ ExclusionList | {$ f.Contains ($ _.?)}) ' – stej

+0

Gracias Richard - puedo usar una matriz de cadenas para $ exclusion. Si miran más de cerca el código, verán que tendré que llamar a get-childitem para cada exclusión. Esto no funcionaría bien si tengo muchas exclusiones. –

+0

@stej: corregirá – Richard

3

Estoy de acuerdo con Richard, que Where-Object debe usarse aquí. Sin embargo, es más difícil de leer. Lo que propongo:

# 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 

También tenga en cuenta que por lo general no es posible iterar sobre una colección y cambiarlo. Tendría una excepción.

$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

Esto es antiguo. Pero, escribí esto hace un tiempo para agregar y eliminar de las listas de Powershell mediante la recursión. Aprovecha la capacidad de powershell para hacer multiple assignment. Es decir, puede hacer $a,$b,[email protected]('a','b','c') para asignar un byc a sus variables. Haciendo $a,[email protected]('a','b','c') asigna 'a'-$a y @('b','c')-$b.

primera es por valor del artículo. Eliminará la primera aparición.

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) 
    } 
} 

Éste se elimina por índice. Probablemente pueda estropearlo pasando un valor para contar en la llamada inicial.

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) 
    } 
} 
Cuestiones relacionadas