Hatena::Groupperl

Press::Alt_R

2010-07-20

Perlわかば (サブルーチンのリファレンス)

例:ファイルを再帰的にたどる

#!perl
use strict;

# -- 自力で決め打ち関数を書くと

my_filefind("./");

# -- ファイルを再帰的に探索してprintする
sub my_filefind{
  my $filename = shift;
  # $filename maybe:
  #  a) file
  #  b) directory
  if ( -f $filename ){print $filename , "\n"; return;}

  return unless ( -d $filename);

  print "----opening dir: $filename\n";
  opendir my $DH , $filename || die("cannot open directory");
  my @filelist = readdir($DH);

  $filename =~ s/\/$//; #remove slash
  foreach my $f(@filelist){
    next if ($f =~ /^\./);
    my_filefind($filename . "/" . $f); # join with slash
  }
  print "----closing dir: $filename\n";
  return;
}

File::Findとcoderefを使う

#!perl
use strict;
use File::Find;

find(\&print_filename , "./");

sub print_filename{
  print $_ , "\n";
}

補足 - 深さのぶん先頭にspaceをとる

# -- 行頭に深さのぶんスペースをつける
sub my_filefind_with_depth{
  my $filename = shift;
  my $depth = shift;

  # $filename maybe:
  #  a) file
  #  b) directory
  if ( -f $filename ){print "  " x $depth , $filename , "\n"; return;}

  return unless ( -d $filename);

  print "  " x $depth , "--dir: $filename\n";
  $depth++;

  opendir my $DH , $filename || die("cannot open directory");
  my @filelist = readdir($DH);
  
  $filename =~ s/\/$//; #remove slash
  foreach my $f(@filelist){
    next if ($f =~ /^\./);
    my_filefind_with_depth( $filename . "/" . $f
                            ,$depth
                          ); # join with slash
  }
  return;
}

補足2: File::Findではディレクトリ探索スタックが使えず……?

各ディレクトリのファイルの数を数える。

counterをスタックにローカル変数として確保できれば、counterを足すだけでよいが、やりかたがわからないのでハッシュに入れている。

#!perl
use strict;
use File::Find;

our %counter = ();

find(
     {
      wanted=>\&print_filename,
      postprocess=>\&aggr_directory,
      preprocess=>\&prepare_directory,
     }
     , "./");

sub print_filename{
  print $_ , "\n";
  $counter{$File::Find::dir}++;
}

sub prepare_directory{
  print "-- dir is:" , $File::Find::dir , "\n";
  return @_; #given list of files
}

sub aggr_directory{
  print "-- " , $counter{$File::Find::dir} ,"\n";
}