How to recursively remove all empty folders in PowerShell?

前端 未结 13 2689
野趣味
野趣味 2020-12-08 02:23

I need to recursively remove all empty folders for a specific folder in PowerShell (checking folder and sub-folder at any level).

At the moment I am using this scrip

13条回答
  •  野趣味
    野趣味 (楼主)
    2020-12-08 02:40

    Just figured I would contribute to the already long list of answers here.

    Many of the answers have quirks to them, like needing to run more than once. Others are overly complex for the average user (like using tail recursion to prevent duplicate scans, etc).

    Here is a very simple one-liner that I've been using for years, and works great...

    It does not account for hidden files/folders, but you can fix that by adding -Force to the Get-ChildItem command

    This is the long, fully qualified cmdlet name version:

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

    So basically...here's how it goes:

    • Get-ChildItem -Recurse -Directory - Start scanning recursively looking for directories
    • $_.EnumerateFiles('*',1) - For each directory...Enumerate the files
      • EnumerateFiles will output its findings as it goes, GetFiles will output when it is done....at least, that's how it is supposed to work in .NET...for some reason in PowerShell GetFiles starts spitting out immediately. But I still use EnumerateFiles because in testing it was reliably faster.
      • ('*',1) means find ALL files recursively.
    • | Select-Object -First 1 - Stop at the first file found
      • This was difficult to test how much it helped. In some cases it helped tremendously, other times it didn't help at all, and in some cases it slowed it down by a small amount. So I really don't know. I guess this is optional.
    • | Remove-Item -Recurse - Remove the directory, recursively (ensures directories that contain empty sub directories gets removed)

    If you're counting characters, this could be shortened to:

    ls -s -ad | ? {-Not $_.EnumerateFiles('*',1) | select -First 1} | rm -Recurse
    
    • -s - alias for -Recurse
    • -ad - alias for -Directory

    If you really don't care about performance because you don't have that many files....even more so to:

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

    Side note: While playing around with this, I started testing various versions with Measure-Command against a server with millions of files and thousands of directories.

    This is faster than the command I've been using (above):

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

提交回复
热议问题