From one File::Find
hater to another: DirWalk.pm
, inspired by the Python’s os.walk()
.
package DirWalk;
use strict;
use warnings;
sub new {
my ($class, @dirs) = @_;
my @odirs = @dirs;
@dirs = qw/./ unless @dirs;
s!/+$!! for @dirs;
s!/+\.$!! for @dirs;
my $self = { _odirs => [@odirs], _dirs => [@dirs], _dhstack => [], _dnstack => [] };
opendir my($dirh), $dirs[0];
return undef unless $dirh;
shift @{ $self->{_dirs} };
unshift @{ $self->{_dhstack} }, $dirh;
unshift @{ $self->{_dnstack} }, $dirs[0];
return bless $self, $class;
}
sub _walk_op {
my ($self) = @_;
if (wantarray) {
my @ret;
while (defined(my $x = $self->next())) {
push @ret, $x;
}
return @ret;
}
elsif (defined wantarray) {
return $self->next();
}
return undef;
}
sub next
{
my ($self) = @_;
my $dstack = $self->{_dhstack};
my $nstack = $self->{_dnstack};
if (@$dstack) {
my $x;
do {
$x = readdir $dstack->[0];
} while (defined($x) && ($x eq '.' || $x eq '..'));
if (defined $x) {
my $nm = $nstack->[0]."https://stackoverflow.com/".$x;
if (-d $nm) {
# open dir, and put the handle on the stack
opendir my($dh), $nm;
if (defined $dh) {
unshift @{ $self->{_dhstack} }, $dh;
unshift @{ $self->{_dnstack} }, $nm;
}
else {
warn "can't walk into $nm!"
}
$nm .= "https://stackoverflow.com/";
}
# return the name
return $nm;
}
else {
closedir $dstack->[0];
shift @$dstack;
shift @$nstack;
unless (@$dstack) {
while (@{ $self->{_dirs} }) {
my $dir = shift @{ $self->{_dirs} };
opendir my($dirh), $dir;
next unless defined $dirh;
unshift @{ $self->{_dhstack} }, $dirh;
unshift @{ $self->{_dnstack} }, $dir;
last;
}
}
return $self->next();
}
}
else {
return undef;
}
}
use overload '<>' => \&_walk_op;
use overload '""' => sub { 'DirWalk('.join(', ', @{$_[0]->{_odirs}}).')'; };
1;
Example:
# prepare test structure
mkdir aaa
touch aaa/bbb
mkdir aaa/ccc
touch aaa/ccc/ddd
# example invocation:
perl -mDirWalk -E '$dw=DirWalk->new("aaa"); say while <$dw>;'
#output
aaa/ccc/
aaa/ccc/ddd
aaa/bbb
Another example:
use strict;
use warnings;
use DirWalk;
# iteration:
my $dw = DirWalk->new("aaa");
while (<$dw>) {
print "$_\n";
}
# or as a list:
$dw = DirWalk->new("aaa");
my @list = <$dw>;
for (@list) {
print "$_\n";
}
5
solved Search file in directory structure