使用 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.
我试过了:
- 使用以下方法保护 foreach
if (!$backups)
- 使用以下方式保护 Remove-Item
if (Test-Path $file -PathType Leaf)
- 使用以下方式保护 Remove-Item
if ([IO.File]::Exists($file.FullName) -ne $true)
这些似乎都不起作用,如果列表为空,推荐的防止进入 foreach 循环的方法会怎样?
答案1
使用 Powershell 3,该foreach
语句不会重复,$null
并且 OP 描述的问题不再出现。
来自Windows PowerShell 博客邮政新的 V3 语言功能:
ForEach 语句不会迭代 $nullForEach statement does not iterate over $null
在 PowerShell V2.0 中,人们常常感到惊讶的是:
PS> foreach ($i in $null) { 'got here' }
got here
当 cmdlet 不返回任何对象时,通常会出现这种情况。在 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
数组中包装的 cmdlet。这也适用于可以返回 的函数$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
}
答案2
我知道这是一篇旧帖子,但我想指出,cmdletForEach-Objec
不会遇到与使用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
可能会有点麻烦,尤其是当你嵌套时,因为很难跟踪引用$_
。无论如何,对于像这样的小操作来说,它是完美的。许多人还声称它更快,但我发现这只是一点点。
答案3
我开发了一个解决方案,通过运行两次查询,一次获取文件,一次通过强制转换 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;
}
}
答案4
使用以下内容评估数组是否包含任何内容:
if($backups.count -gt 0) { echo "Array has contents" } else { echo "Array is empty" }
如果变量不存在,Powershell 将简单地将其评估为 false,因此无需检查它是否存在。