Link to home
Start Free TrialLog in
Avatar of TheDadCoder
TheDadCoder

asked on

Batch script to delete empty folders?

Hi all,

Following on from some excellent help from knightEknight on this script:
https://www.experts-exchange.com/questions/28273418/Script-to-find-duplicate-files-but-not-using-filename-filesize.html


I'm now in need of a script to recursively search for and delete empty folders.

so i have a root folders called:

+Media

This has say 3 folders, with one of the folders having a subfolder:

+Folder1
+Folder2
+Folder3
....+Folder3a

Only Folder2 has files in it, all of the others need to be deleted.


Any idea how to write a batch file to achieve this?

Thanks,
Avatar of Bill Prew
Bill Prew

Here's a simple VBS script that can be used to do what you described, save as a VBS and update the base dir path at the top.

It currently prints the folders it removes, but if you want it to run silently just remove the Wscript.Echo line.

Const strBaseDir = "C:\EE\EE28281260\Files"

set objFSO = WScript.CreateObject("Scripting.FileSystemObject")

RemoveFolder objFSO.GetFolder(strBaseDir)

Sub RemoveFolder(objFolder)
    For Each objSubFolder In objFolder.Subfolders
        RemoveFolder objSubFolder
    Next
    If objFolder.Files.Count = 0 And objFolder.Subfolders.Count = 0 Then
        Wscript.Echo objFolder.Path
        objFolder.Delete
    End If
End Sub

Open in new window

~bp
If you have cygwin or other Unix environment installed on your Windows then you can do it with a very simple shell command.
find . -depth -type d -empty -exec rmdir {} \;

Open in new window


I was going to use find2perl to generate a perl script to do it but apparently find2perl doesn't support -empty so it becomes more difficult...
Avatar of TheDadCoder

ASKER

Hi billprew - thanks I'll try that script.

Hi wilcoxon, I'm not using cygwin or any unix system here, thanks anyway.
Hi billprew, I've tested your vbs script and for normal files it works, of course.

However, I've noticed that some folders that appeared empty it failed to delete them.  upon inspection this was due to hidden files, such as thumbs.db.

Any ideas how it can still delete if it finds a file that's to delete?

or is it just easier to do a windows find and delete first?
It depends.  Are all the files in the "empty" directories 0-size files so should be removed by the script?  If so, you need to do a depth-first traversal so it will see the 0-size files before it checks if the directory is empty.
Hi - no these are system files that store icon pos values, and other stuff, which in this situation are not needed.

I'm thinking a list of files to always delete... but it might just be easier to delete these via windows search first.
A list of filenames to always delete or to delete only if they are the only files in a folder (eg leave alone if the folder is not otherwise empty) should work fine.  I should have time tomorrow sometime to work up a perl solution...
Sounds like it might be easiest, and safest, to just delete the desired files, and then run the script to remove the empty folders.

~bp
Here's a perl solution...
use strict;
use warnings;
use File::Find ();

# for the convenience of &wanted calls, including -eval statements:
use vars qw/*name *dir *prune/;
*name   = *File::Find::name;
*dir    = *File::Find::dir;
*prune  = *File::Find::prune;

use Cwd ();
my $cwd = Cwd::cwd();

my $base = shift || 'C:/EE/EE282281260/Files'; # pass in or default

# change this to include the files you want to remove if they are the
# only ones in the directory
my @files_to_rm = (qw(thumbs.db anotherfile and_another));
my %files_to_rm = map { $_ => 1 } @files_to_rm;

# Traverse desired filesystems
File::Find::finddepth({wanted => \&wanted}, $base);
exit;

sub wanted {
    my ($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_);
    if (-f _ and int(((-s _) + 511) / 512) == 0) {
        unlink $name or die "could not rm $name: $!";
    } elsif (-d _) {
        opendir DIR, $name or die "could not open dir $name: $!";
        my @files = grep !m{^\.+$}, readdir DIR;
        closedir DIR;
        my @del = grep { exists $files_to_rm{$_} } @files;
        # there are no files or all files are ones to remove
        if (@files == @del or @files == 0) {
            foreach my $fil (@files) {
                unlink "$name/$fil" or die "could not rm $name/$fil: $!";
            }
            system('rmdir', $name) == 0 or die "rmdir failed: $?";
        }
    }
}

Open in new window

Give this a try:

Const strBaseDir = "C:\EE\EE28281260\Files"

arrFilesToDelete = Array("thumbs.db", "desktop.ini")

set objFSO = WScript.CreateObject("Scripting.FileSystemObject")

RemoveFolder objFSO.GetFolder(strBaseDir)

Sub RemoveFolder(objFolder)
    For Each objSubFolder In objFolder.Subfolders
        RemoveFolder objSubFolder
    Next
    For Each objFile in objFolder.Files
        For Each strFileToDelete in arrFilesToDelete
            If LCase(strFileToDelete) = LCase(objFile.Name) Then
                objFile.Delete(True)
            End If
        Next
    Next
    If objFolder.Files.Count = 0 And objFolder.Subfolders.Count = 0 Then
        Wscript.Echo objFolder.Path
        objFolder.Delete
    End If
End Sub

Open in new window

~bp
Another script to test :)
Just wondering if you've had time to test the perl script I submitted?  If so, any issues with how it worked?
Hi wilcoxon - how do you run the perl script?

billprew - yours works as needed thanks.
Hi billprew,

I added an additional filename to the script as below but I get an error now.   I guess it doesn't like the mac os filename '.DS_Store'?


Any ideas?

invalid procedure call or arguement
code: 800A0005
Line: 21:
char: 8


Const strBaseDir = "v:\"

arrFilesToDelete = Array("thumbs.db", "desktop.ini", ".DS_Store")

set objFSO = WScript.CreateObject("Scripting.FileSystemObject")

RemoveFolder objFSO.GetFolder(strBaseDir)

Sub RemoveFolder(objFolder)
    For Each objSubFolder In objFolder.Subfolders
        RemoveFolder objSubFolder
    Next
    For Each objFile in objFolder.Files
        For Each strFileToDelete in arrFilesToDelete
            If LCase(strFileToDelete) = LCase(objFile.Name) Then
                objFile.Delete(True)
            End If
        Next
    Next
    If objFolder.Files.Count = 0 And objFolder.Subfolders.Count = 0 Then
       objFolder.Delete
    End If
End Sub

Open in new window

Hi billprew - ignore my last comment.  It deletes the files with the new filename fine, however the error seems to come from the delete command when the basedir is empty, i.e. nothing to delete, but it tries to delete anyway, but since there's nothing to delete it fails.

Not a major issue, but it'd be nice to return an message saying "Nothing to delete!", or something.

Is this possible?
So are you saying there are no files or folders under v:\, but it is trying to delete v:\? Naturally deleting a root folder of a drive will fail, that's not allowed, but I'm surprised you are actually empty on v:\?

We would actually want to check the folder name I suspect, and handle this special case, the root folder, if that's what you are seeing.

~bp
Sorry.  You had posted in the Perl topic so I assumed you knew how to run Perl...

In order to run a perl script, you need to have perl installed.  If you are on Mac, I'm pretty sure it is standard.  If you are on Windows then you probably need to install one - I'd suggest Strawberry Perl.

Once it is installed, you should be able to type "perl <script name> <script arguments>" (replacing the items in <> with the actual names/values).  If you are on Windows, you'll likely need to open "Perl (command line)" (or something similar) rather than the normal command prompt to run it (I'm not sure why it gets installed that way as I believe the only difference is some environment variables).
Hi billprew,  v: drive is just a mapped drive to my polling folder, nothing special.  The end result would be that folder, that v drive points to, is empty.  or not empty and i know i have files i need to clear out manually.

I don't know if it's trying to delete v drive, but the code looks like it's running the delete command but i suspect there's nothing to delete.

This is confusing because your last section eval's if files and folder count =0.
ASKER CERTIFIED SOLUTION
Avatar of Bill Prew
Bill Prew

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Just perfect, thank you.
Why no recent comments about my script and no splitting of the points?  The perl script I submitted did exactly what you requested.
Hi  wilcoxon,

I thank you for assistance, however I voted to use the alt script as it was quicker to just use, rather than install perl.

Thanks anyway.
May I suggest, in future, not including the "Perl Programming Language" topic if you don't want to install Perl?
you may.
Welcome.

~bp