如何以递归方式删除PowerShell中的所有空文件夹?

Gib*_*boK 30 powershell window windows-8.1

我需要以递归方式删除PowerShell中特定文件夹的所有空文件夹(任何级别的checing文件夹和子文件夹).

目前我使用这个脚本没有成功.

你能告诉我怎么解决吗?

$tdc='C:\a\c\d\'
$a = Get-ChildItem $tdc -recurse | Where-Object {$_.PSIsContainer -eq $True}
$a | Where-Object {$_.GetFiles().Count -eq 0} | Select-Object FullName
Run Code Online (Sandbox Code Playgroud)

我在Win 8.1上使用PowerShell

arc*_*444 36

你可以用这个:

$tdc="C:\a\c\d"
$dirs = gci $tdc -directory -recurse | Where { (gci $_.fullName).count -eq 0 } | select -expandproperty FullName
$dirs | Foreach-Object { Remove-Item $_ }
Run Code Online (Sandbox Code Playgroud)

$dirs将是Get-ChildItem过滤后从命令返回的空目录数组.然后,您可以循环它以删除项目.

更新

如果要删除包含空目录的目录,只需继续运行脚本,直到它们全部消失为止.你可以循环直到$dirs空:

$tdc="C:\a\c\d"
do {
  $dirs = gci $tdc -directory -recurse | Where { (gci $_.fullName).count -eq 0 } | select -expandproperty FullName
  $dirs | Foreach-Object { Remove-Item $_ }
} while ($dirs.count -gt 0)
Run Code Online (Sandbox Code Playgroud)

如果要确保还将删除隐藏的文件和文件夹,请包含以下-Force标志:

do {
  $dirs = gci $tdc -directory -recurse | Where { (gci $_.fullName -Force).count -eq 0 } | select -expandproperty FullName
  $dirs | Foreach-Object { Remove-Item $_ }
} while ($dirs.count -gt 0)
Run Code Online (Sandbox Code Playgroud)


Kir*_*nro 36

在查看这样的问题时,您需要记住一些关键事项:

  1. Get-ChildItem -Recurse执行头递归,这意味着它在遍历树时找到它们时立即返回文件夹.由于您要删除空文件夹,并且在删除空文件夹后删除它们的父项(如果它们为空),则需要使用尾递归,它将处理从最深的子项到根的文件夹.通过使用尾递归,不需要重复调​​用删除空文件夹的代码 - 一个调用将为您完成所有操作.
  2. 默认情况下,Get-ChildItem不会返回隐藏文件或文件夹.因此,您需要采取额外步骤以确保不删除显示为空但包含隐藏文件或文件夹的文件夹.Get-Item和Get-ChildItem都有一个-Force参数,可用于检索隐藏文件或文件夹以及可见文件或文件夹.

考虑到这些要点,这里有一个使用尾递归并正确跟踪隐藏文件或文件夹的解决方案,确保删除隐藏文件夹(如果它们为空)并确保保留可能包含一个或多个隐藏文件的文件夹:

# A script block (anonymous function) that will remove empty folders
# under a root folder, using tail-recursion to ensure that it only
# walks the folder tree once. -Force is used to be able to process
# hidden files/folders as well.
$tailRecursion = {
    param(
        $Path
    )
    foreach ($childDirectory in Get-ChildItem -Force -LiteralPath $Path -Directory) {
        & $tailRecursion -Path $childDirectory.FullName
    }
    $currentChildren = Get-ChildItem -Force -LiteralPath $Path
    $isEmpty = $currentChildren -eq $null
    if ($isEmpty) {
        Write-Verbose "Removing empty folder at path '${Path}'." -Verbose
        Remove-Item -Force -LiteralPath $Path
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很棒的答案.编辑待处理以注释代码还会删除开始文件夹,如果它结束为空. (5认同)
  • @KirkMunro我在technet和其他地方遇到了一些不能正常工作的答案,你已经找到了我见过的唯一一个好的答案. (4认同)
  • 请注意,这也将删除根文件夹,我的贡献是验证 if RootPath <> Path,然后删除 { if ($IsEmpty && $Path -ne $RootPath) { Write-Verbose "Removingemptyfolder at path '${小路}'。” -详细}} (2认同)

cha*_*win 14

只是想我会对这里已经很长的答案列表做出贡献。

许多答案都有怪癖,比如需要运行多次。其他对于普通用户来说过于复杂(例如使用尾递归来防止重复扫描等)。

这是一个非常简单的单行文字,我已经使用了多年,而且效果很好......

它不考虑隐藏文件/文件夹,但您可以通过添加-ForceGet-ChildItem命令来修复该问题

这是长的、完全限定的 cmdlet 名称版本:

Get-ChildItem -Recurse -Directory | ? { -Not ($_.EnumerateFiles('*',1) | Select-Object -First 1) } | Remove-Item -Recurse
Run Code Online (Sandbox Code Playgroud)

所以基本上......事情是这样的:

  • Get-ChildItem -Recurse -Directory- 开始递归扫描寻找目录
  • $_.EnumerateFiles('*',1)- 对于每个目录...枚举文件
    • EnumerateFiles将在运行时输出其发现,GetFiles将在完成时输出......至少,这就是它在.NET中应该如何工作......出于某种原因,在PowerShell中GetFiles立即开始吐出。但我仍然使用,EnumerateFiles因为在测试中它确实更快。
    • ('*',1)表示递归查找所有文件。
  • | Select-Object -First 1- 停在找到的第一个文件处
    • 很难测试它有多大帮助。在某些情况下,它有很大帮助,而在其他时候,它根本没有帮助,在某些情况下,它会稍微减慢速度。所以我真的不知道。我想这是可选的。
  • | Remove-Item -Recurse- 递归地删除目录(确保删除包含空子目录的目录)

如果您正在计算字符数,则可以缩短为:

ls -s -ad | ? { -Not ($_.EnumerateFiles('*',1) | select -First 1) } | rm -Recurse
Run Code Online (Sandbox Code Playgroud)
  • -s- 别名-Recurse
  • -ad- 别名-Directory

如果您真的不关心性能,因为您没有那么多文件......更重要的是:

ls -s -ad | ? {!($_.GetFiles('*',1))} | rm -Recurse
Run Code Online (Sandbox Code Playgroud)

旁注:在尝试这个过程时,我开始针对Measure-Command具有数百万个文件和数千个目录的服务器测试各种版本。

这比我一直使用的命令(上面)更快:

(gi .).EnumerateDirectories('*',1) | ? {-Not $_.EnumerateFiles('*',1) } | rm -Recurse
Run Code Online (Sandbox Code Playgroud)


Loï*_*HEL 5

ls c:\temp -rec |%{ if ($_.PSIsContainer -eq $True) {if ( (ls $_.fullname -rec | measure |select -expand count ) -eq "0"  ){ ri $_.fullname -whatif}  }  }  
Run Code Online (Sandbox Code Playgroud)

  • 感谢您的解释。但是,如果 c:\temp 不存在,它似乎会尝试访问整个硬盘驱动器,因此最好首先检查该目录是否存在。 (2认同)

Bac*_*its 5

Get-ChildItem $tdc -Recurse -Force -Directory | 
    Sort-Object -Property FullName -Descending |
    Where-Object { $($_ | Get-ChildItem -Force | Select-Object -First 1).Count -eq 0 } |
    Remove-Item -Verbose
Run Code Online (Sandbox Code Playgroud)

这里唯一的新颖贡献是Sort-Object用于按目录FullName进行反向排序。这将确保我们在处理父母之前总是先处理孩子。这使得它以递归方式删除空文件夹。

暂时而言,我不确定是否Select-Object -First 1会有意义地提高性能,但是确实可以。