我有一个分享,是最终用户的“垃圾抽屉”。他们可以根据需要创建文件夹和子文件夹。我需要实现一个脚本来删除超过31天创建的文件。
我从Powershell开始。我需要通过删除现在为空的子文件夹来跟进文件删除脚本。由于子文件夹的嵌套,我需要避免删除没有文件的子文件夹,但在其下面有一个包含文件的子文件夹。
例如:
FILE3a
已有10天之久。 FILE3
已有45天。C:\Junk\subfolder1a\subfolder2a\FILE3a
C:\Junk\subfolder1a\subfolder2a\subfolder3a
C:\Junk\subfolder1a\subfolder2B\FILE3b
期望的结果:
FILE3b
,subfolder2B
& subfolder3a
。 subfolder1a
,subfolder2a
和FILE3a
。我可以递归清理文件。如何在不删除subfolder1a
的情况下清理子文件夹? (“垃圾”文件夹将始终保留。)
答案 0 :(得分:43)
我会在两次传递中执行此操作 - 首先删除旧文件,然后删除空目录:
Get-ChildItem -recurse | Where {!$_.PSIsContainer -and `
$_.LastWriteTime -lt (get-date).AddDays(-31)} | Remove-Item -whatif
Get-ChildItem -recurse | Where {$_.PSIsContainer -and `
@(Get-ChildItem -Lit $_.Fullname -r | Where {!$_.PSIsContainer}).Length -eq 0} |
Remove-Item -recurse -whatif
这种类型的操作演示了第二组命令演示的PowerShell中嵌套管道的强大功能。它使用嵌套管道递归确定任何目录下是否有零文件。
答案 1 :(得分:9)
根据第一个答案的精神,这是删除空目录的最短方法:
ls -recurse | where {!@(ls -force $_.fullname)} | rm -whatif
当目录具有隐藏文件夹(例如.svn
)时,需要使用-force标志答案 2 :(得分:4)
这将在父目录解决空嵌套目录问题之前对子目录进行排序。
dir -Directory -Recurse |
%{ $_.FullName} |
sort -Descending |
where { !@(ls -force $_) } |
rm -WhatIf
答案 3 :(得分:3)
添加到最后一个:
while (Get-ChildItem $StartingPoint -recurse | where {!@(Get-ChildItem -force $_.fullname)} | Test-Path) {
Get-ChildItem $StartingPoint -recurse | where {!@(Get-ChildItem -force $_.fullname)} | Remove-Item
}
这将使其完整继续搜索以删除$ StartingPoint
下的任何空文件夹答案 4 :(得分:2)
删除超过30天的文件:
get-childitem -recurse |
? {$_.GetType() -match "FileInfo"} |
?{ $_.LastWriteTime -lt [datetime]::now.adddays(-30) } |
rm -whatif
(只需删除-whatif
即可实际执行。)
跟进:
get-childitem -recurse |
? {$_.GetType() -match "DirectoryInfo"} |
?{ $_.GetFiles().Count -eq 0 -and $_.GetDirectories().Count -eq 0 } |
rm -whatif
答案 5 :(得分:2)
我需要一些企业友好的功能。这是我的看法。
我从其他答案的代码开始,然后添加了一个带有原始文件夹列表的JSON文件(包括每个文件夹的文件数)。删除了空目录并记录下来。
https://gist.github.com/yzorg/e92c5eb60e97b1d6381b
param (
[switch]$Clear
)
# if you want to reload a previous file list
#$stat = ConvertFrom-Json (gc dir-cleanup-filecount-by-directory.json -join "`n")
if ($Clear) {
$stat = @()
} elseif ($stat.Count -ne 0 -and (-not "$($stat[0].DirPath)".StartsWith($PWD.ProviderPath))) {
Write-Warning "Path changed, clearing cached file list."
Read-Host -Prompt 'Press -Enter-'
$stat = @()
}
$lineCount = 0
if ($stat.Count -eq 0) {
$stat = gci -Recurse -Directory | %{ # -Exclude 'Visual Studio 2013' # test in 'Documents' folder
if (++$lineCount % 100 -eq 0) { Write-Warning "file count $lineCount" }
New-Object psobject -Property @{
DirPath=$_.FullName;
DirPathLength=$_.FullName.Length;
FileCount=($_ | gci -Force -File).Count;
DirCount=($_ | gci -Force -Directory).Count
}
}
$stat | ConvertTo-Json | Out-File dir-cleanup-filecount-by-directory.json -Verbose
}
$delelteListTxt = 'dir-cleanup-emptydirs-{0}-{1}.txt' -f ((date -f s) -replace '[-:]','' -replace 'T','_'),$env:USERNAME
$stat |
? FileCount -eq 0 |
sort -property @{Expression="DirPathLength";Descending=$true}, @{Expression="DirPath";Descending=$false} |
select -ExpandProperty DirPath | #-First 10 |
?{ @(gci $_ -Force).Count -eq 0 } | %{
Remove-Item $_ -Verbose # -WhatIf # uncomment to see the first pass of folders to be cleaned**
$_ | Out-File -Append -Encoding utf8 $delelteListTxt
sleep 0.1
}
# ** - The list you'll see from -WhatIf isn't a complete list because parent folders
# might also qualify after the first level is cleaned. The -WhatIf list will
# show correct breath, which is what I want to see before running the command.
答案 6 :(得分:1)
这对我有用。
$limit = (Get-Date).AddDays(-15)
$path = "C:\Some\Path"
删除早于$limit
的文件:
Get-ChildItem -Path $path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit } | Remove-Item -Force
删除旧文件后删除所有遗留的空目录:
Get-ChildItem -Path $path -Recurse -Force | Where-Object { $_.PSIsContainer -and (Get-ChildItem -Path $_.FullName -Recurse -Force | Where-Object { !$_.PSIsContainer }) -eq $null } | Remove-Item -Force -Recurse