using standard module: use File::Find; find({ wanted => sub { # for each file # $_ is file name # $File::Find::name is full path # $File::Find::dir is directory path }, preprocess => sub { # process the list of files about to be wanted() # $File::Find::dir is directory path return @_; }, follow => 0, # follow symlinks? no_chdir => 0, # dont chdir (so $_ equals $File::Find::name) }, @directories); manually: use strict; sub act { my ($file) = @_; print "$file\n"; } sub traverse { my ($path,$wildcard) = @_; $path =~ s#/+$##; # Could be more efficient with an opendir for my $file (glob("$path/*")) { next unless (-d $file); # actions to dirs go here traverse($file,$wildcard); } for my $file (glob("$path/$wildcard")) { act($file) if (-f $file); } } my $path = $ARGV[0] || '.'; my $wildcard = $ARGV[1] || '*'; &traverse($path,$wildcard);