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

hello everyone!

i've poked around here, using the Search and SuperSearch, and the closest i've come up with is this.

What i'm really trying to do is to find a set of files, and concatenate them all together into one big file, in time-order.

To that end, i need my script to do something like:
find . -name threads.html -maxdepth 3 -mindepth 3
File::Find seems to be the right thing, and it's apparently wizardly and flexible beyond my means... so i tried out find2perl, but recieved this response:
find2perl find . -name threads.html -maxdepth 3 -mindepth 3 Unrecognized switch: -maxdepth

The depth is important, as there are "threads.html" files both in the 2 and 4 sublevels of the current directory, and they must not be included... however, sometimes this script will be operating on one of those subdirectories, and will still need to collect files from 3 levels below the current working directory.

find2perl tells me that this is what i want, minus the -maxdepth and -mindepth switches:

File::Find::find({wanted => \&wanted}, 'find', '.'); sub wanted { /^threads\.html\z/s; }

and that even makes sense to me, except that i cannot figure out how to modify it to emulate the -max|mindepth values.

In any case, thanks for reading this!

Replies are listed 'Best First'.
Re: find2perl with File::Find and -maxdepth
by samtregar (Abbot) on Jun 02, 2002 at 06:08 UTC
    Easily done:

    #!/usr/bin/perl -w use strict; use File::Find; # set these to the desired min and max my $max_depth = 3; my $min_depth = 3; # find files my @files; find({ wanted => sub { my $depth = tr!/!!; # count slashes to get depth return if $depth < $min_depth or $depth > $max_depth; push @files, $_; }, no_chdir => 1 }, '.' ); # sort by mtime @files = sort { (stat($a))[9] <=> (stat($b))[9] } @files; # concat and print foreach my $file (@files) { open FILE, $file or die "Can't open $_ : $!"; while (<FILE>) { print } }

    Of course, that's just one way to do it. You could improve it by using a Schwarzian Transform to save time in the sort. Or you could build you script to be called as part of a pipe from the real find.

    I suppose it might be nice to teach find2perl to output this trick. Maybe after 5.8.0.

    -sam

(tye)Re: find2perl with File::Find and -maxdepth
by tye (Sage) on Jun 02, 2002 at 06:30 UTC

    I'd go with something much simpler:     my @files= glob( "*/*/*/threads.html" ); with the knowledge that it might not work on some "fringe" operating systems. ;)

            - tye (but my friends call me "Tye")
      Hey thanks guys!

      tye, i think i'll have to go with sam's version, since there's potentially hundreds of thousands of such files, and i really only want to work on ones created in the last 60 days or so... and i'm pretty sure i can do that with the File::Find stuff.

      But, your 'simpler' solution is pretty elegant, given a *nix machine (which is indeed the case here).

      sam, i think you should post your work here in the 'snippets' section or something, it's a rather useful thing to be able to do (if you need to), and find2perl doesn't do it... i'm sure other newbies could benefit.

      Thanks again folks!

        BTW, this works on more than just Unix. And it is easy to skip files that don't fit in a date range:

        my @files= grep -C $_ <= 60, glob( "*/*/*/threads.html" );
        Though this loads the entire list of files before it is stripped down so it still might not work for you.

                - tye (but my friends call me "Tye")
Re: find2perl with File::Find and -maxdepth
by u914 (Pilgrim) on Jun 02, 2002 at 05:48 UTC
    Hmm.. There seems to be no (obvious to me) way to edit or revise one's initial post here...

    In any case, i've yet to really solve this problem, but i've worked around it using a call directly to the underlying OS's find function. i had to open it at a filehandle to get the output back, so system didn't seem workable.

    i don't like this because it's quite non-portable (important to me since i'm developing on linux, but this will run on an old solaris box), but.... well, it works.

    Here's the find_test.pl code i came up with:

    #!/usr/bin/perl -w # This is a poor way to list filenames using all the available # switches for your local 'find' command. It could probably be # better accomplished with File::Find, but i was not able to # make that work. use strict; use Data::Dumper 'Dumper'; # here you can use whatever arguments you like.... open FIND, "find . -name *.html -maxdepth 3 -mindepth 3 |"; # a large number, MAXLINE if you're being conscientous read FIND, my $find_output, 99999; # the find output is returned as one big string, so split it my @files = split(/\n/, $find_output); # dump the raw find output. note that it's all one value, # with \n (newline) in it. print Dumper [$find_output]; # now dump the array.. each 'hit' on it's own position print Dumper [@files]; exit 0;

    If anyone has a better way to do this, i'm highly interested!