The following program gives different results depending on whether I save the source with Unix or Mac linebreaks.
I could well be the reason is a logic error of mine. I haven't checked thoroughly. BTW: I found the program very useful as a replacement for Unix "find". Axel --- #!/usr/local/bin/perl -w ### remove if modules are in their own files { package WalkTree; use strict; my $DIRSEP = $^O =~ /Mac/ ? ':' : $^O =~ /Win|OS-2|DOS/ ? '\\' : '/'; my $MACOS = ( $^O =~ /Mac/ ) || 0; my $WINOS = ( $^O =~ /Win|OS-2|DOS/ ) || 0; sub walktree { my ( $dir, $filefunc, $dirfunc, $prune ) = @_; $MACOS and $dir =~ s/:$//; if ( -d $dir ) { if( defined $prune ) { return undef if $dir =~ /$prune/o } my @values; local *DH; opendir DH, $dir or warn "opendir '$dir' failed\n$!"; my $file; while ( defined( $file = readdir DH )) { !$MACOS and next if( $file eq '.' or $file eq '..' ); $MACOS and next if( $file eq "Icon\n" ); push @values, walktree( "$dir$DIRSEP$file", $filefunc, $dirfunc, $prune ); } closedir DH; ref $dirfunc ? return $dirfunc->($dir, @values) : return @values; } else { ref $filefunc ? return $filefunc->($dir) : return; } } 1; } ### remove if modules are in their own files ### remove if modules are in their own files { package File; use strict; # encapsulate { # value 0 makes an attribute non-writable my %_attributes = ( name => 1, ); my $_attributes = sub { keys %_attributes }; my $_cnt; my $_incr_cnt = sub{ $_cnt++ }; sub get_cnt { $_cnt } sub new { my ($caller, %arg) = @_; my $caller_is_obj = ref( $caller ); my $class = $caller_is_obj || $caller; my $self = bless {}, $class; foreach my $member ( $_attributes->() ) { if( $arg{ $member } ) { $self->{ $member } = $arg{ $member } } } my @stat = stat( $self->get_name ); # hash slice assignement @{$self}{ "dev", "inode", "mode", "nlink", "uid", "gid", "rdev", "size", "atime", "mtime", "ctime", "blksize", "blocks" } = @stat; $_incr_cnt->(); return $self; } } sub get_name { return $_[0]->{name} } sub get_dev { return $_[0]->{dev} } sub get_inode { return $_[0]->{inode} } sub get_mode { return $_[0]->{mode} } sub get_nlink { return $_[0]->{nlink} } sub get_uid { return $_[0]->{uid} } sub get_gid { return $_[0]->{gid} } sub get_rdev { return $_[0]->{rdev} } sub get_size { return $_[0]->{size} } sub get_atime { return $_[0]->{atime} } sub get_mtime { return $_[0]->{mtime} } sub get_ctime { return $_[0]->{ctime} } sub get_blksize { return $_[0]->{blksize} } sub get_blocks { return $_[0]->{blocks} } 1; } ### remove if modules are in their own files ### package main; use strict; require 5.005; use Getopt::Std; ### if packages go into external files ### use WalkTree; ### use File; # search directory start my $dir; my $filter; my $prune; process_args(); my $filefunc = sub { if( defined $filter ) { $_[0] =~ /$filter/o and File->new( name => $_[0] ) } else { File->new( name => $_[0] ) } }; my @files = grep { ref } WalkTree::walktree( $dir, $filefunc, undef, $prune ); unless( @files ) { exit 1 } print File->get_cnt(), " files found\n"; print "list of found files with size info:\n", "-" x 40, "\n"; for my $file ( @files ) { # still possible but we're into OO now # print $file->{name}, "\n"; print $file->get_size, "\t", $file->get_name, "\n"; } # just for demonstration (and because I always forget) my @name_and_mtime = map{ { name => $_->get_name, mtime => $_->get_mtime } } @files; my @mtime_sorted = sort { $a->{mtime} <=> $b->{mtime} } @name_and_mtime; print "mtime sorted list of found files:\n", "-" x 40, "\n"; for ( @mtime_sorted ) { print $_->{mtime}, "\t", $_->{name}, "\n"; } print "=" x 40, "\n"; print "runtime: ", time - $^T, " seconds.\n"; print "done.\n"; ### end of main ### sub process_args { my $MACOS = ( $^O =~ /Mac/ ) || 0; unless( @ARGV ) { if( $MACOS ) { @ARGV = split / /, MacPerl::Ask( 'Please enter @ARGV (-h for help)' ); $dir = ":"; $ARGV[0] and -d $ARGV[0] and $dir = $ARGV[0]; } !$MACOS and $dir = '.'; } usage() if ! $ARGV[0] or $ARGV[0] =~ /-h/; my %opts; getopts( 'f:p:h', \%opts ); if( $opts{f} ) { eval { $filter = qr/$opts{f}/ } or warn "regex '$opts{f}' cannot be compiled, continuing without filter\n"; } if( $opts{p} ) { eval { $prune = qr/$opts{p}/ } or warn "regex '$opts{p}' cannot be compiled, continuing without pruning\n"; } ## print "DEBUG: dir = $dir, filter = $filter, prune = ", defined $prune ? $prune : "undef", "\n"; } sub usage { print <<eom; $0 -f <filter> -p <prune> -h <search directory start> all arguments are optional default filter is undef default prune is undef defaults search directory search directory is current working directory eom exit 1; } __END__ =head1 NAME walktree-finder-oo.pl =head1 SYNOPSIS walktree-finder-oo.pl -f <filter> -p <prune> -h <search directory start> all arguments are optional default filter is undef default prune is undef defaults search directory search directory is current working directory example: walktree-finder-oo.pl -f '\.pl$' /usr/local/bin searches for files ending with .pl in directory /usr/local/bin for MacOS: enter command line options in the displayed dialog as -f \.pl$ 'Macintosh HD:Desktop Folder:myprojects:' =head1 DESCRIPTION Demonstration of OO techniques, replacement of File::Find for shortness and flexibility. WalkTree was taken from "The Idendity Function" slides provided by Mark-Jason Dominus at http://www.plover.com/~mjd/ =head1 BUGS/TODO =head1 AUTHOR =head1 VERSION $Id$ =cut