1: This code came from my desire to use perl for something
   2: besides CGI, which is my current perl-y focus.
   3: I expected slightly different behavior from
   4: File::Find::file, though this may be my Win background
   5: shining through.
   6: Put simply, this will traverse a filesystem, and determine
   7: the # of files based on extention. Again, this was more to
   8: keep the programming muscles limber; I plan on using this as a shell for more complex things. I do appreciate any
   9: comments you have, however.
  10: <code>
  11: #use warnings;
  12: use strict;
  13: use File::Find;
  14: 
  15: my %hash;
  16: my @temp;
  17: 
  18: File::Find::find (\&wanted,"c:\\");
  19: my @keys = keys (%hash);
  20: @keys = sort_by_value (\%hash);
  21: 
  22: 
  23: print "-"x20,"\n";
  24: foreach my $key(@keys) {if ($key =~ /^$/) {print "no ext\t:\t"}else{  print "$key\t:\t"}; print $hash{$key},"\n"}
  25: 
  26: sub sort_by_value {
  27:     my %hash = %{shift()};
  28:     sort {$hash {$a} <=> $hash{$b}  } keys %hash;
  29: }
  30: 
  31: 
  32: sub wanted {
  33: my @file ;
  34: my $fname;
  35:     #   don't attempt to read a directory.
  36:     if (-d $_) {return};
  37:     $fname = $File::Find::name;
  38:     #   turn any '/' into a '\'
  39:     #   then make sure that any '\\' get turned into '\'
  40:     $fname =~ s#\/#\\#g;
  41:     $fname =~ s#\\\\#\\#;
  42:     @temp= split  /\./, $_;
  43:     #   mmm. autovivification
  44:     $hash{@temp[1]}++
  45: }
  46: </code>

Replies are listed 'Best First'.
Re: file ext counter.
by chromatic (Archbishop) on Nov 23, 2000 at 10:35 UTC
    While I applaud your use of references to create complex data structures, you can save some memory and speed by operating on the hash directly:
    sub sort_by_value { my $hash = shift; sort {$hash->{$a} <=> $hash->{$b} } keys %$hash; }
    I won't ask why you declare @keys and then immediately clobber it. :) (I often forget to delete test code, too.)
Re: file ext counter.
by lemming (Priest) on Nov 22, 2000 at 21:17 UTC
    This line:
    use warnings; use strict; use File::Find; my %hash; my @temp; my $dir = shift @ARGV; die "Give me a directory to search\n" unless (-d "$dir"); File::Find::find (\&wanted,"$dir"); print "-"x20,"\n"; foreach my $key (sort keys %hash) { print $key, "\t:\t",$hash{$key},"\n"; } sub wanted { # don't attempt to read a directory. return if (-d $_); my $fname = $File::Find::name; @temp = split(/[\/\\]/, $fname); $fname = $temp[-1]; # Make sure there is an extension. We check for a # trailing period even though on Win32 it shouldn't happen if (($fname =~ /\./) && !($fname =~ /\.$/)) { $fname = lc($fname); @temp= split(/\./, $fname); $hash{$temp[-1]}++; } else { $hash{"no ext"}++; } }

    Update:
    I Changed a few more things around. I went right for the filename since a "." in a directory could mess things up as well.
    $array[-1] so that we don't have troubles with files like "blah.txt.sh".
    And we now account for no extension at all.
    This code could make use of File::Basename as well.
      ah, I see why you'd want to use  $hash{@temp[-1]}++ but this exhibits bad behavior for files with no extention at all! update

      your

      if (($fname =~ /\./) && !($fname =~ /\.$/)) { $fname = lc($fname); @temp= split(/\./, $fname); $hash{$temp[-1]}++; } else { $hash{"no ext"}++; }
      seems a little clumsy. consider
      if ($#temp >0) {$hash{@temp[-1]}++} else {$hash{""}++}
      which sees if there's more than 1 bucket in @temp. If there is, we know the lastmost one's the extention. If there isn't we know the filename has no extention. in fact, I think this can be shortened to <code> if ($#temp) <code> but that's not a big deal. I kept the hash named "" for the highly special case of a file, e.g. "foo.no ext"