[Solved] Search file in directory structure


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