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

Hi Monks

(Original question) I'm trying to get a script to look for csv files less than 5500 bytes.

I have the code below finding the csv's but thats the limit of my knowledge using File:Find.

(Updated question) I have multiple folders under c:\Temp each containing .csv files, ideally I'd like to only list the folders containing .csv files under 5500 bytes not each .csv file.

Any help would be appreciated.

P.s I can't install other File:Find module alternatives (Due to work policies).

use strict; use warnings; use File::Find; my @files; my $dir = 'C:\\Temp\\'; find( \&csvfile, $dir ); foreach my $list (@files) { print "$list\n"; sub csvfile { push @files, $File::Find::name if -f && /\.csv/; } }

Replies are listed 'Best First'.
Re: Looking for small csv files script question
by choroba (Cardinal) on Dec 03, 2013 at 23:35 UTC
    Just add -s:
    push @files, $File::Find::name if -f && /\.csv/ && -s < 5500;
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      Thanks I'll give that a go.

      I thought this might do the trick (It's doing something at least).

      sub csvfile { if ((stat($File::Find::name))[7] <= 5500) { push @files, $File::Find::name if -f && /\.csv/; } }

        Tried your example and it comes up with this.

        Warning: Use of "-s" without parentheses is ambiguous at csvfile.pl line 21. syntax error at csvfile.pl line 21, near "/\.csv/ -s " Unterminated <> operator at csvfile.pl line 21.

Re: Looking for small csv files script question
by runrig (Abbot) on Dec 04, 2013 at 01:13 UTC
    FYI, -f does another stat. To save a stat() use '_':
    sub csvfile { /\.csv$/ or return; stat; -f _ or return; -s _ < 5500 or return; push @files, $File::Find::name; }
      Thanks for replying, I'll give that a go as well.
Re: Looking for small csv files script question
by Tux (Canon) on Dec 04, 2013 at 07:09 UTC

    Of course you can install other File::Find variants. Just search PerlMonks to see how. But why would you?

    As others already showed here, it is extremely simple with File::Find. Once you are used to the idiom, you'll even start writing these quests in short versions:

    use File::Find; my @files; find (sub { m/\.csv$/i && -s $_ < 5500 and push @files, $File::Find::N +ame }, "C:/Temp"); say for sort @files;

    Enjoy, Have FUN! H.Merijn

      Hi Tux, thanks for your short version reply. I'll have to start trying these!

      It gets trickier though, I have updated my original question.

        In sticking with the core modules so that you don't have to install any new modules, here's some untested code that is basically a modified version of what Tux provided that handles your new requirement.

        use File::Find; use File::Basename; use feature 'say'; my @files; find (sub { m/\.csv$/i && -s $_ < 5500 and push @files, $File::Find::N +ame }, "C:/Temp"); my %dirs; foreach my $file (@files) { my($filename, $directories, $suffix) = fileparse($file); $dirs{$directories}++; } my @keys = keys %dirs; @keys = sort @keys; foreach my $key (@keys) {say $key;}

        Basically, what I've done is taken the array of files that meet your criteria and then putting their path (minus filename) into a hash where the path is a key in the hash (and the value for the key is the count of files in that folder that meet your criteria). Then I'm sorting the keys and printing them out. Hopefully, this will help get your further into solving your problem.

Re: Looking for small csv files script question
by dasgar (Priest) on Dec 04, 2013 at 06:57 UTC

    I'm not saying the other suggestions are wrong, but those suggestions are using some syntax that I personally don't understand - at least not without looking up documentation and/or doing some testing. That's why I would prefer going with something that I find easier to read and understand. Just a personal preference.

    I haven't tested this, but the code below is something that I believe should accomplish what you're wanting to do and is something that I personally find much easier to read and understand.

    use strict; use warnings; use File::Find::Rule; my $target = 'C:\temp'; my $rule = File::Find::Rule->new; $rule->file; # Look for files (-f test) $rule->name('*.csv'); # Look for filenames ending in .csv $rule->size(<5500); # Look for a size of less than 5500 bytes my @files = $rule->in($target); # The @files array will have the files that meet the 'rules' above.

    I realize that this doesn't go well with your comment that you "can't install other File:Find module alternatives". Out of curiosity, why are you limited by not installing any modules?

      Hi Dasgar, thanks for your example. It looks simple enough, unfortunately it's a battle with our I.T Dept to get anything installed hence the File::Find only option.

        I'm not advocating that you should totally disregard's your employer's IT policies, but if your system at work has access to the internet and/or has a USB port that you can use, you can still get use Perl and "install" other modules.

        Since the path in your example code was "C:\Temp", I'm assuming that you're on Windows. In that case, I'd recommend checking out Strawberry Perl. It comes with everything you need to install modules from CPAN. They also have a portable version, which doesn't actually install Perl onto your system. Instead, you need to run a batch file that they provide in order to use their portable version.

        So if you really want to use other modules, I'd agree with Tux that there are ways to get that done.