Используя Powershell v2.0, я хочу удалить любые файлы старше X дней:
$backups = Get-ChildItem -Path $Backuppath |
Where-Object {($_.lastwritetime -lt (Get-Date).addDays(-$DaysKeep)) -and (-not $_.PSIsContainer) -and ($_.Name -like "backup*")}
foreach ($file in $backups)
{
Remove-Item $file.FullName;
}
Однако, когда $ backups пуст, я получаю: Remove-Item : Cannot bind argument to parameter 'Path' because it is null.
Я пробовал:
if (!$backups)
if (Test-Path $file -PathType Leaf)
if ([IO.File]::Exists($file.FullName) -ne $true)
Кажется, что ни один из них не работает, что делать, если рекомендуемый способ предотвращения входа в цикл foreach, если список пуст?
С Powershell 3 foreach
оператор не повторяется $null
и проблема, описанная OP, больше не возникает.
Из Блог Windows PowerShell Почта Новые возможности языка V3:
Оператор ForEach не выполняет итерацию по $ null
В PowerShell V2.0 людей часто удивляли:
PS> foreach ($i in $null) { 'got here' }
got here
Такая ситуация часто возникает, когда командлет не возвращает никаких объектов. В PowerShell V3.0 вам не нужно добавлять оператор if, чтобы избежать итерации по $ null. Мы позаботимся об этом за вас.
Для PowerShell $PSVersionTable.PSVersion.Major -le 2
см. следующий исходный ответ.
У вас есть два варианта, я в основном использую второй.
Проверьте $backups
для не $null
. Простой If
вокруг цикла можно проверить, нет ли $null
if ( $backups -ne $null ) {
foreach ($file in $backups) {
Remove-Item $file.FullName;
}
}
Или
Инициализировать $backups
как нулевой массив. Это позволяет избежать двусмысленности проблемы "повторения пустого массива". вы спрашивали в своем последнем вопросе.
$backups = @()
# $backups is now a null value array
foreach ( $file in $backups ) {
# this is not reached.
Remove-Item $file.FullName
}
Извините, я не предоставил пример интеграции вашего кода. Обратите внимание Get-ChildItem
командлет, завернутый в массив. Это также будет работать с функциями, которые могут возвращать $null
.
$backups = @(
Get-ChildItem -Path $Backuppath |
Where-Object { ($_.lastwritetime -lt (Get-Date).addDays(-$DaysKeep)) -and (-not $_.PSIsContainer) -and ($_.Name -like "backup*") }
)
foreach ($file in $backups) {
Remove-Item $file.FullName
}
Я знаю, что это старый пост, но я хотел бы отметить, что командлет ForEach-Object не страдает той же проблемой, что и использование ключевого слова ForEach. Таким образом, вы можете передать результаты DIR в ForEach и просто сослаться на файл с помощью $ _, например:
$backups | ForEach{ Remove-Item $_ }
Фактически вы можете перенаправить саму команду Dir через конвейер и даже не назначать переменную, например:
Get-ChildItem -Path $Backuppath |
Where-Object {
($_.lastwritetime -lt (Get-Date).addDays(-$DaysKeep)) -and `
(-not $_.PSIsContainer) -and ($_.Name -like "backup*")
} |
ForEach{ Remove-Item $_ }
Я добавил разрывы строк для удобства чтения.
Я понимаю некоторых людей, которым нравится ForEach / In для удобства чтения. Иногда ForEach-object может показаться непростым, особенно если вы выполняете вложение, так как становится трудно следовать ссылке $ _. Во всяком случае, для такой небольшой операции он идеален. Многие люди также утверждают, что это быстрее, но я обнаружил, что это не так.
Я разработал решение, выполнив запрос дважды, один раз для получения файлов и один раз для подсчета файлов, приведя get-ChilItem для возврата массива (преобразование $ backups в качестве массива после факта, похоже, не работает) .
По крайней мере, он работает так, как ожидалось (производительность не должна быть такой проблемой, поскольку никогда не будет больше дюжины файлов), если кто-то знает решение для одного запроса, опубликуйте его.
$count = @(Get-ChildItem -Path $zipFilepath |
Where-Object {($_.lastwritetime -lt (Get-Date).addDays(-$DaysKeep)) -and (-not $_.PSIsContainer) -and ($_.Name -like $partial + "*")}).count;
if ($count -gt 0)
{
$backups = Get-ChildItem -Path $zipFilepath |
Where-Object {($_.lastwritetime -lt (Get-Date).addDays(-$DaysKeep)) -and (-not $_.PSIsContainer) -and ($_.Name -like $partial + "*")};
foreach ($file in $backups)
{
Remove-Item $file.FullName;
}
}
Используйте следующее, чтобы оценить, есть ли в массиве какое-либо содержимое:
if($backups.count -gt 0) { echo "Array has contents" } else { echo "Array is empty" }
Если переменная не существует, Powershell просто оценит ее как ложную, поэтому нет необходимости проверять, существует ли она.