Solved

Batch script to delete empty folders?

Posted on 2013-10-30
25
2,519 Views
Last Modified: 2013-12-16
Hi all,

Following on from some excellent help from knightEknight on this script:
http://www.experts-exchange.com/Programming/Languages/Scripting/Shell/Batch/Q_28273418.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,
0
Comment
Question by:TheDadCoder
  • 11
  • 8
  • 6
25 Comments
 
LVL 51

Expert Comment

by:Bill Prew
ID: 39612150
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
0
 
LVL 26

Expert Comment

by:wilcoxon
ID: 39612198
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...
0
 

Author Comment

by:TheDadCoder
ID: 39620229
Hi billprew - thanks I'll try that script.

Hi wilcoxon, I'm not using cygwin or any unix system here, thanks anyway.
0
 

Author Comment

by:TheDadCoder
ID: 39624752
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?
0
 
LVL 26

Expert Comment

by:wilcoxon
ID: 39624948
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.
0
 

Author Comment

by:TheDadCoder
ID: 39625118
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.
0
 
LVL 26

Expert Comment

by:wilcoxon
ID: 39625499
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...
0
 
LVL 51

Expert Comment

by:Bill Prew
ID: 39626161
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
0
 
LVL 26

Expert Comment

by:wilcoxon
ID: 39626515
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

0
 
LVL 51

Expert Comment

by:Bill Prew
ID: 39649975
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
0
 

Author Comment

by:TheDadCoder
ID: 39654394
Another script to test :)
0
 
LVL 26

Expert Comment

by:wilcoxon
ID: 39661341
Just wondering if you've had time to test the perl script I submitted?  If so, any issues with how it worked?
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

Author Comment

by:TheDadCoder
ID: 39680972
Hi wilcoxon - how do you run the perl script?

billprew - yours works as needed thanks.
0
 

Author Comment

by:TheDadCoder
ID: 39681031
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

0
 

Author Comment

by:TheDadCoder
ID: 39681056
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?
0
 
LVL 51

Expert Comment

by:Bill Prew
ID: 39681176
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
0
 
LVL 26

Expert Comment

by:wilcoxon
ID: 39681448
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).
0
 

Author Comment

by:TheDadCoder
ID: 39692089
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.
0
 
LVL 51

Accepted Solution

by:
Bill Prew earned 500 total points
ID: 39694483
Thy this small workaround.

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
       If Len(objFolder.Path) > 3 Then
           objFolder.Delete
       End If
    End If
End Sub

Open in new window

~bp
0
 

Author Closing Comment

by:TheDadCoder
ID: 39721338
Just perfect, thank you.
0
 
LVL 26

Expert Comment

by:wilcoxon
ID: 39721467
Why no recent comments about my script and no splitting of the points?  The perl script I submitted did exactly what you requested.
0
 

Author Comment

by:TheDadCoder
ID: 39721992
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.
0
 
LVL 26

Expert Comment

by:wilcoxon
ID: 39722130
May I suggest, in future, not including the "Perl Programming Language" topic if you don't want to install Perl?
0
 

Author Comment

by:TheDadCoder
ID: 39722152
you may.
0
 
LVL 51

Expert Comment

by:Bill Prew
ID: 39722227
Welcome.

~bp
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Many time we need to work with multiple files all together. If its windows system then we can use some GUI based editor to accomplish our task. But what if you are on putty or have only CLI(Command Line Interface) as an option to  edit your files. I…
If like me you are one who spends a lot of time working and scripting with cmd.exe, sometimes it is handy to be able to quickly view a calendar for a given month and year. This script will quickly do just that!  Save the code posted below to a .bat …
Learn the basics of if, else, and elif statements in Python 2.7. Use "if" statements to test a specified condition.: The structure of an if statement is as follows: (CODE) Use "else" statements to allow the execution of an alternative, if the …
Learn the basics of modules and packages in Python. Every Python file is a module, ending in the suffix: .py: Modules are a collection of functions and variables.: Packages are a collection of modules.: Module functions and variables are accessed us…

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now