Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Re^2: aborting File::Find::find (gotchas)

by tye (Sage)
on Nov 16, 2006 at 22:19 UTC ( [id://584618]=note: print w/replies, xml ) Need Help??


in reply to Re: aborting File::Find::find
in thread aborting File::Find::find

Did you:

grep DONE: File/Find.pm

before you wrote this code? Do you do that for every label you have ever used this way each time you upgrade File::Find? I'd have more sympathy for going against the first paragraph of "perldoc -f goto"1 if Perl supported the following syntax:

File::Find::find( sub { ... goto My::Package::FOUND ... } ... ); My::Package::FOUND: ....

Does that give you a better feel why some people are not in favor of such a practice?

I suspect that using last to exit a sub generates a warning because it is widely considered a bad practice and last is used enough that accidentally using it to exit a subroutine appeared on the radar. So the warning for last and not for goto has more to do with last being seen as useful and used while goto is not. In particular, the lack of a warning is not an indication that the practice is not seen as a bad one (sorry, I wanted one more negation in there but I grew tired).

I shy aware from using things that the documentation tells me that I shouldn't. Those are the things that get "fixed" to no longer work or that aren't well tested and so nobody notices when they break and so bugs in them survive into "stable" releases.

I shy aware from practices that break just because someone else somewhere also came up with "DONE" for their label name.

But I do see the appeal of such simple and clear code (once the reader gets over the shock of using goto to jump out of a possibly large number of subroutine calls, that is).

BTW, my solution for this problem would probably be to spend less time rolling a dozen-line replacement for File::Find then I'd have to spend searching the File::Find docs to see if it supported a "thanks, I'm done" feature. The classic gotchas are well known to me2 (as well as the failings of File::Find that have caused me grief repeatedly over the many years when I've been unfortunate enough to try to use it or try to use something that used it).

Here, an example I threw together in a couple of minutes:

BEGIN { my( $dot, $up )= ( File::Spec->curdir(), File::Spec->updir() ); sub SearchDirs { my( $path, $subdir )= @_; $path= File::Spec->catdir( $path, $subdir ); chdir $subdir or die "Can't chdir, $path: $!\n"; opendir D, $dot or die "Can't opendir, $path: $!\n"; my @files= grep $_ ne $dot && $_ ne $up, readdir D; closedir D; for( @files ) { my $recurse= ! -l $_ && -d _; # ... SearchDirs( $path, $_ ) if $recurse; } chdir $up or die "Can't chdir .. from $path: $!\n"; } }

Using the above would mean that I at least wouldn't have to worry about "goto DONE;" suddenly not working because I upgraded File::Find.

Just for fun, let's avoid that whole problem and make return work by eliminating the recursion:

#!/usr/bin/perl -w use strict; use File::Spec; # Globals: my( $FiNode, $FnLinks, @Found ); Main( @ARGV ); exit( 0 ); BEGIN { my( $dot, $up )= ( File::Spec->curdir(), File::Spec->updir() ); sub SearchDirs { my( $path )= @_; my @depth= "."; my @todo= ( ".", $path ); while( @todo ) { my $path= shift @todo; my $subdir= shift @todo; while( $path ne $depth[-1] ) { chdir $up or die "Can't chdir .. from $depth[-1]: $ +!\n"; pop @depth; } $path= File::Spec->catdir( $path, $subdir ); push @depth, $path; chdir $subdir or die "Can't chdir, $path: $!\n"; opendir D, $dot or die "Can't opendir, $path: $!\n"; my @files= grep $_ ne $dot && $_ ne $up, readdir D; closedir D; for( @files ) { push @todo, $path, $_ if ! -l $_ && -d _; if( $FiNode == ( lstat _ )[1] ) { push @Found, File::Spec->catfile( $path, $_ ); return if --$FnLinks < 1; } } } } } sub Main { die "Usage: file dir\n" if 2 != @_; my( $fpath, $dir )= @_; ( $FiNode, $FnLinks )= ( lstat $fpath )[1,3]; if( 1 == $FnLinks ) { print $fpath, $/; } else { SearchDirs( $dir ); print $_, $/ for @Found; } }

It even works. (:

- tye        

1 Quote: It can be used to go almost anywhere else within the dynamic scope, including out of subroutines, but it's usually better to use some other construct such as "last" or "die".

2 Such as:

  1. Either use chdir and opendir on File::Spec->curdir() or prepend the path before using stat-like operations
  2. Skip File::Spec->curdir() and ->updir() or you'll loop forever
  3. Don't recurse into symbolic links (or keep a hash of where you've been or just assert that circular links cause infinite loops)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://584618]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (5)
As of 2024-04-25 07:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found