Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Yea, though i walk through the shadow of File::Find & Directory Tree Deletion...

by wufnik (Friar)
on Jul 12, 2004 at 22:49 UTC ( [id://373765]=perlquestion: print w/replies, xml ) Need Help??

wufnik has asked for the wisdom of the Perl Monks concerning the following question:

ok. File::Find. earlier today, i was looking rather smugly at Jendas node on File::Find; File::Find considered hard?, thinking how *i* would not be caught by the vagaries of the module, thinking even how i would start using merlyns File::Finder, once i had completed a simple task - removing directories via File::Find.

after all, there is a recipe for it in the perl cookbook. nothing could go wrong...

several fraught hours later, my confidence & hubris had dissolved in the acid of File::Find... to boot, my presumption led to the deletion of many funky files in my dat directory. after much wailing and gnashing of teeth, i appeal for advice, and hayulp...

the following script takes directories as arguments, and attempts, quite simply, to delete them after deleting all files inside them. actually, it's a little more generic than that - it is recursive directory deleter, and will delete any subdirectory inside the directories mentioned. it half works, be careful! i should mention, it's pretty much directly stolen from the cookbook.

# rmdirsimple.pl use File::Find qw(finddepth); use Cwd; *name = *File::Find::name; my @dirs = @ARGV; my @legitdirs = grep { -d } @dirs; finddepth (\&unlinkplus, @legitdirs); # danger, danger. high voltage. use at own risk. sub unlinkplus { warn "current dir :" . cwd . "\n"; if (!-l && -d _) { # not a link, is a directory warn "rmdir attempt :" . $name . "\n"; (rmdir($_) && warn "ok..." ) or warn "cannot rmdir $name:" . " $!"; } else { warn "file unlink :" . $name . ">"; (unlink($_) && warn "ok..." ) or warn "can't unlink " . $name . "$!"; } }
now, run this through cygwin perl (5.8.2), using something like
/usr/bin/perl rmdirsimple.pl a b
where a and b are directories that contain a.txt and b.txt respectively, and you will get a satisfying:
current dir :/home/k/kh/prlfrg/dat/a file unlink :a/a.txt> at rmdirsimple.pl line 20. ok... at rmdirsimple.pl line 21. current dir :/home/k/kh/prlfrg/dat/a rmdir attempt :a ok... at rmdirsimple.pl line 17. current dir :/home/k/kh/prlfrg/dat/b file unlink :b/b.txt> at rmdirsimple.pl line 20. ok... at rmdirsimple.pl line 21. current dir :/home/k/kh/prlfrg/dat/b rmdir attempt :b ok... at rmdirsimple.pl line 17.
run it through activestate (5.6.1) perl - and the deletion of the directories seems impossible: here's the results:
current dir :C:/cygwin/home/k/kh/prlfrg/dat/a file unlink :a/a.txt> at rmdirsimple.pl line 20. ok... at rmdirsimple.pl line 21. current dir :C:/cygwin/home/k/kh/prlfrg/dat/a rmdir attempt :a cannot rmdir a: Permission denied at rmdirsimple.pl line 17. current dir :C:/cygwin/home/k/kh/prlfrg/dat/b file unlink :b/b.txt> at rmdirsimple.pl line 20. ok... at rmdirsimple.pl line 21. current dir :C:/cygwin/home/k/kh/prlfrg/dat/b rmdir attempt :b cannot rmdir b: Permission denied at rmdirsimple.pl line 17.
most depressing. i am sure that it's because the process is sitting in the directory it is attempting to delete. but if this *is* the case, how did rmtree1 from the cookbook ever... get into the cookbook! and does anyone know how the above problem might be solved within the confines of activestate perl?

many thanks for any help
...wufnik

-- in the world of the mules there are no rules --

Replies are listed 'Best First'.
Re: Yea, though i walk through the shadow of File::Find & Directory Tree Deletion...
by ysth (Canon) on Jul 12, 2004 at 23:37 UTC
    cygwin goes through a lot of hoops to delete open files when they close or when your process ends; don't know if this applies to directories also, but if so it would explain the difference.

    Have you tried using the no_chdir option of File::Find?

      THIS WORKS for activestate - thanks++ ysth. thanks also to the other monks that have responded.

      specifically, when i change the code to:
      use File::Find qw(find); use Cwd; *name = *File::Find::name; my @dirs = @ARGV; my @legitdirs = grep { -d } @dirs; find( { "wanted" => \&unlinkplus, "bydepth"=>1, "no_chdir"=>1 } , @leg +itdirs); # danger, danger. high voltage. use at own risk. sub unlinkplus { warn "current dir :" . cwd . "\n"; if (!-l && -d _) { # not a link, is a directory warn "rmdir attempt :" . $name . "\n"; (rmdir($_) && warn "ok..." ) or warn "cannot rmdir $name:" . " $!"; } else { warn "file unlink :" . $name . ">"; (unlink($_) && warn "ok..." ) or warn "can't unlink " . $name . "$!"; } }
      i get the behavior i require, ie removal of directories after the files in them have been removed, no problems. in summary: if you are using activestate perl for this kind of thing, ie directory removal, make sure you have the no_chdir option on.

      if you are sensible enough to use cygwin perl, you will have no problems here. both versions of the script will work.

      ps: re: tachyon's question (ie: rm -r) ; the restraining bolt fitted to prevent overtly sensible behavior is due to come off soon...

      ...wufnik

      -- in the world of the mules there are no rules --
Re: Yea, though i walk through the shadow of File::Find & Directory Tree Deletion...
by DrHyde (Prior) on Jul 13, 2004 at 08:27 UTC
    Your solution seems a little too clever to me. You're deleting as you go through the tree. I'd break the task into two steps:
    1. find everything to be deleted;
    2. second, delete it
    So use File::Find (a module whose interface I hate, try File::Find::Rule instead) to push everything into an array as you find it, then ...

    foreach (reverse @array) { (-d && rmdir) || (-f && unlink) }

    Note the reverse - you'll find parent directories before their contents, but need to delete them afterwards.

    Alternatively, if you unshift data into the array, the reverse isn't needed. But IMO pushing is better, as it's more widely used and understood.

Re: Yea, though i walk through the shadow of File::Find & Directory Tree Deletion...
by toma (Vicar) on Jul 13, 2004 at 06:14 UTC
    File::Flat has a clever API which pretends that directories don't exist. It also has 'can' methods to check if operations, such as deletion, are allowed.

    For me File::List is the easiest way to search a directory tree.

    It should work perfectly the first time! - toma
Re: Yea, though i walk through the shadow of File::Find & Directory Tree Deletion...
by tachyon (Chancellor) on Jul 13, 2004 at 00:36 UTC

    Why not use rm -rf <dir> <list>?

    cheers

    tachyon

      Since cygwin working isn't good enough, the OP probably needs it to work in the absence of unix tools. But there is File::Path::rmtree.
Re: Yea, though i walk through the shadow of File::Find & Directory Tree Deletion...
by Mr. Muskrat (Canon) on Jul 12, 2004 at 23:30 UTC
    It looks like the user running the script does not have the proper permissions to access the files that live under Cygwin. I could however be wrong (would definitely not be the first time).
      i checked this, permissioning having bitten me before -

      I *can* remove a simple empty directory using a perl rmdir call, from activestate perl, successfully, provided i have not cd'd to the location of the directory. the directory to be deleted should be empty when the problem script above gets to it, so i think the thing that is stopping the script from functioning is not permissioning, or the fact that there is a file there -

      i think it is more the fact that the chdir implicit in File::Find is preventing the action of rmdir, but am still testing...

      thanks anyway -
      ...wufnik

      -- in the world of the mules there are no rules --
Re: Yea, though i walk through the shadow of File::Find & Directory Tree Deletion...
by rinceWind (Monsignor) on Jul 13, 2004 at 10:43 UTC
    You might like to try my module File::Wildcard hot off the press. It works on Windows as well as Unix platforms.

    --
    I'm Not Just Another Perl Hacker

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://373765]
Approved by Paladin
Front-paged by grinder
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (3)
As of 2024-03-29 06:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found