Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Recursive Directory Tree Deletion in Windows

by gaggio (Friar)
on Oct 18, 2000 at 17:49 UTC ( #37326=perlquestion: print w/ replies, xml ) Need Help??
gaggio has asked for the wisdom of the Perl Monks concerning the following question:

Well, here's a little script request that I'm sure some of you, my friends, have already come across at some point...

I have a directory tree, containing MANY files and MANY subdirectories, and I would like to be able to delete directories matching a specified pattern along with all the files (and maybe subdirectories) that they contain... something that the poor DEL command is far from being able to do!

Thanks for a quick help.

Comment on Recursive Directory Tree Deletion in Windows
RE: Recursive Directory Tree Deletion in Windows
by arturo (Vicar) on Oct 18, 2000 at 18:12 UTC

    Probably what you want is File::Find, which will recurse subdirectories for you and you can specify what to do with each file. Read up on it around this site, there are a number of threads concerning how to use it.

    Philosophy can be made out of anything -- or less

      Well, File::Find should help you out. But if not, do a SuperSearch on File::Find.
RE: Recursive Directory Tree Deletion in Windows
by cwest (Friar) on Oct 18, 2000 at 18:34 UTC
RE: Recursive Directory Tree Deletion in Windows
by gaggio (Friar) on Oct 18, 2000 at 19:50 UTC
    I looked for a thread that had the answer I needed, but I could not find any. Thank you very much for voting me down for no reason!

    I'd like some comments.
Re: Recursive Directory Tree Deletion in Windows
by djw (Vicar) on Oct 18, 2000 at 20:22 UTC
    Like the others said use File::Find::finddepth to recursively toast directories (obviously be very careful with this as it acts exactly like rm -r). If you have the perl cookbook there is an explination on page 325 of this exact thing.

    If you don't have that then take a look at the code in the File:Find module (win32: %perl_install_dir%\lib\File\Find.pm ).

    Also remember that the 'rmdir' command won't delete directories if they have files and/or subdirectories still in them.


    Thanks,
    djw
RE: Recursive Directory Tree Deletion in Windows
by gaggio (Friar) on Oct 18, 2000 at 20:30 UTC
    I am so mean, that I even give the script away now.
    I think that you really should keep voting me down! (there are always going to be things that I won't understand in the world, even in nice places like PM:-( )

    Note: the script might have to be run several times, because it does not delete directories when they still have files in them. - Just keep running it until 0 file and 0 directory are deleted.

    #!/usr/local/bin/perl -w use File::Find; $workingdir = 'C:/TEMP/'; $countdirs = 0; $countfiles = 0; $testmode = 0; @extensions = ('txt','obj'); #files to remove @directories = ('win32-VC60','CVS','Cvs'); #directories to remove (rec +ursively with all the files/subs in them) @anymatches = ('ChangeLog'); #other special matches to remove as well find(\&processmatch, $workingdir); print "\n$countfiles file(s) and $countdirs director(y)(ies) were dele +ted.\n\n"; sub processmatch{ # Note: we are chdir in the current directory! $saved = $_; $name = $File::Find::name; $deleteflag = 0; foreach $ext(@extensions) { if($name =~ /.*\.$ext/) { $deleteflag = 1; } } foreach $dir(@directories) { if($name =~ /.*\/$dir.*/) { $deleteflag = 1; } } foreach $any(@anymatches) { if($name =~ /.*$any.*/) { $deleteflag = 1; } } if($deleteflag == 1) { if (-d $name) { if(!$testmode) { rmdir $name; } print "$name\n"; $countdirs++; } else { if(!$testmode) { unlink $saved; } print "$saved\n"; $countfiles++; } } $_ = $saved; }

    BTW: Thanks for the persons who helped me!
      the script might have to be run several times, because it does not delete directories when they still have files in them. - Just keep running it until 0 file and 0 directory are deleted.

      Use finddepth() instead of find() to have File::Find report all of a directory's entries before reporting the directory name itself. Depth-first searching allows you do clean out a directory before you try to delete it.

Re: Recursive Directory Tree Deletion in Windows
by the_slycer (Chaplain) on Oct 18, 2000 at 21:39 UTC
    As it happens I was working on something similar to this last nite. I spent a couple of hours on it before I discovered File::Find - I really have to read more, might be able to stop duplicating effort. Anyhow, here is the code that I wrote, someone let me know what problems there are.. other than the obvious dup of effort :-).
    use strict; unless ($ARGV[0]){ print "Please enter a string to look for: "; $ARGV[0]=<STDIN>; chomp @ARGV; } my $delkey = $ARGV[0]; my $startdir="c:/blah"; my (@dirs, @newdirs, @dellist); print "searching $startdir\n"; #build a list of files/dirs: my @list = glob("$startdir*"); #run through the list, if a dir, goes to @dir array (with a / at the e +nd) foreach (@list){ push (@dirs => "$_/") if -d; if (/.*$delkey*/oi){ push (@dellist => "$_/") if -d; } } #call the subroutine - this does the same thing on the next set of dir +s down build(@dirs); #if there are further subdirs, call the sub again while (@newdirs){ build($newdirs[0]); shift(@newdirs); } sub build{ my @dirs=@_; while (@dirs){ my $dir = shift (@dirs); print "searching $dir\n"; my @list = glob("$dir*"); foreach (@list){ push (@newdirs => "$_/") if -d; if (/.*$delkey*/oi){ push (@dellist => "$_/") if -d; } } } } foreach (reverse @dellist){ print "found: $_ to delete\n"; chdir "$_" || die "Unable to change to $_ : $!"; unlink (<*>); chdir "$startdir" || die "Unable to change back to $startdir : $!" +; rmdir "$_" || die "Unable to rmdir on $_ : $!"; }
Re: Recursive Directory Tree Deletion in Windows
by OzzyOsbourne (Chaplain) on Oct 18, 2000 at 22:12 UTC
    You can pick out what you need...
    # ********************************* # Call Modules # ********************************* use File::Find; use File::Copy; use Getopt::Std; getopts('d:h'); # ********************************* # Initialize variables # ********************************* $server='server104'; $dir1='\\\\'."$server".'\\d$'; $agedays=60; #defaults agedays to 60 # ********************************* # Process arguments ([h]elp,[d]ays) # ********************************* if ($opt_h){ die "\agecmd.pl -d[days to age]\n"; } if ($opt_d){ if ($opt_d gt 9){ #tests for strings die "Error: days option must be a number. Use agecmd.pl -d[da +ys to age]\n"; }else{ $agedays=$opt_d; } } # ********************************* # Do date calculations # ********************************* @xtime=localtime(time); $day=$xtime[3]+1; $month=$xtime[4]+1; $year=$xtime[5]+1900; $hours=$xtime[2]; $mins=$xtime[1]; $secs=$xtime[0]; $logname='//server1/d$/'."ftp$month$day$year$hours$mins$secs".'.log'; $agesecs=60*60*24*$agedays; #converts $agedays to seconds $daysago=time-$agesecs; #the time stamp of $agedays ago in seco +nds $daysago2=localtime($daysago); #the time stamp of $agedays ago in w +ords - mainly for printing # ********************************* # Find the files (no dir) on the server # ********************************* print "finding files to be aged\.\.\.\n"; find(\&wanted, $dir1); sub wanted { $filesecs = (stat("$File::Find::dir/$_"))[9]; #GETS THE 9TH ELEMEN +T OF file STAT - THE MODIFIED TIME $filesecs2=localtime($filesecs); if ($filesecs<$daysago && -f){ #-f=regular files, eliminates DIR p +.367 push (@files,"$File::Find::dir/$_"); push (@files,"$filesecs2"); } print'.'; } # ********************************* # replace '/' with '\' in file names # ********************************* foreach (@files){ s/\//\\/g; } # ********************************* # Write to Log # ********************************* %filehash=@files; #puts the array into a hash for easy printing. Key= +file, Value=date open OUT, ">$logname" or die "Cannot open $out for write :$!"; print OUT "FTP server aging log generated by PERL script\n"; print OUT "Script written by Ozzy on 4/18/00\n"; print OUT "Files deleted from \\\\$server on ".localtime(time)."\n"; print OUT "Files deleted before $daysago2\n"; print OUT "Files were aged $agedays days\n\n"; print OUT "File Listing:\n\n"; foreach $filename (sort keys %filehash){ print OUT "$filename $filehash{$filename}\n"; } close OUT; # ********************************* # Delete files # ********************************* print "\nDeleting all files before $daysago2"; #unlink %filehash; print "\nScript complete.";

    -OzzyOsbourne

Re: Recursive Directory Tree Deletion in Windows
by Anonymous Monk on Oct 20, 2000 at 03:50 UTC
    Am I missing something, or is the underlying OS command relevant here?
    C:\WINDOWS>deltree -? Deletes a directory and all the subdirectories and files in it. To delete one or more files and directories: DELTREE [/Y] [drive:]path [[drive:]path[...]] /Y Suppresses prompting to confirm you want to delete t +he subdirectory. [drive:]path Specifies the name of the directory you want to dele +te. Note: Use DELTREE cautiously. Every file and subdirectory within the s +pecified directory will be deleted.
      First - he only wants to recursively delete directories that match a particular string. Secondly - deltree is suspiciously missing on Windows 2000 :-(
        Win2K uses `rmdir`, no more deltree (same functionality though)

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://37326]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (7)
As of 2015-05-28 17:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    In my home, the TV remote control is ...









    Results (562 votes), past polls