Samy_rio has asked for the wisdom of the Perl Monks concerning the following question:

G'day monks, I have a problem in File::DirWalk. My tried code as:

use strict; use warnings; use File::DirWalk; my $folder = 'E:\test\foldersize\1-folder|E:\test\foldersize\2-folder| +E:\test\foldersize\5-folder'; my $depth = 3; my @directory = grep!/^\s*$/, split/\|/, $folder; my @folder; for my $directory (@directory){ my $dw = new File::DirWalk; $dw->onDirLeave(sub { my ($dir) = @_; return File::DirWalk::FAILED if ($dir eq $directory); push (@folder, $dir); return File::DirWalk::SUCCESS; }); $dw->setDepth($depth); $dw->walk($directory); } $,="\n"; print @folder;

Output as:

E:\test\foldersize\1-folder\Allworth\Copy of VTT E:\test\foldersize\1-folder\Allworth\VTT E:\test\foldersize\1-folder\Allworth E:\test\foldersize\1-folder\Brepols\ARA E:\test\foldersize\1-folder\Brepols E:\test\foldersize\1-folder\Else_UK\KAST2 E:\test\foldersize\1-folder\Else_UK E:\test\foldersize\2-folder\Allworth\VTT E:\test\foldersize\2-folder\Allworth E:\test\foldersize\2-folder\Brepols\ARA E:\test\foldersize\2-folder\Brepols E:\test\foldersize\2-folder\Else_UK\KAST2 E:\test\foldersize\2-folder\Else_UK E:\test\foldersize\5-folder\Allworth\VTT E:\test\foldersize\5-folder\Allworth E:\test\foldersize\5-folder\Brepols\ARA E:\test\foldersize\5-folder\Brepols E:\test\foldersize\5-folder\Else_UK\KAST2 E:\test\foldersize\5-folder\Else_UK

But i need only last folder path. That is, 3rd depth folder path only.

E:\test\foldersize\1-folder\Allworth\Copy of VTT E:\test\foldersize\1-folder\Allworth\VTT E:\test\foldersize\1-folder\Brepols\ARA E:\test\foldersize\1-folder\Else_UK\KAST2 E:\test\foldersize\2-folder\Allworth\VTT E:\test\foldersize\2-folder\Brepols\ARA E:\test\foldersize\2-folder\Else_UK\KAST2 E:\test\foldersize\5-folder\Allworth\VTT E:\test\foldersize\5-folder\Brepols\ARA E:\test\foldersize\5-folder\Else_UK\KAST2

How to acheive this? Any special function available in File::DirWalk itself? Thanks in advance.

Velusamy R.

eval"print uc\"\\c$_\""for split'','j)@,/6%@0%2,`e@3!-9v2)/@|6%,53!-9@2~j';

Replies are listed 'Best First'.
Re: Array Normalization of File::DirWalk
by Enlil (Parson) on Feb 23, 2007 at 07:39 UTC
    Since you are printing the directories on the way out you should be able to just do the following:
    use strict; use warnings; use File::DirWalk; my $folder = 'E:\test\foldersize\1-folder|E:\test\foldersize\2-folder| +E:\te +st\foldersize\5-folder'; my $depth = 3; my @directory = grep!/^\s*$/, split/\|/, $folder; my @folder; my %dirs; for my $directory (@directory){ my $dw = new File::DirWalk; $dw->onDirLeave( sub { my ($dir) = @_; if ( !exists $dirs{$dir} ) { if( $dir =~ /(.*)\\/ ) { undef($dirs{$1}); } push (@folder, $dir); } return File::DirWalk::SUCCESS; } ); $dw->setDepth($depth); $dw->walk($directory); } print $_,$/ for @folder
    and hence it won't print any directory that has any directories in it.
Re: Array Normalization of File::DirWalk
by graff (Chancellor) on Feb 23, 2007 at 08:16 UTC
    Looking at the output you're getting, it seems like File::DirWalk is doing its traversal in such a way that the deeper paths are listed first, and assuming that will always be the case, then Enlil's suggestion should work fine.

    There's another way, which would not be dependent on the assumption that the original listing will always be ordered like that, but it involves post-processing after the DirWalk thing is done:

    @folder = sort @folder; my $npaths = scalar @folder; push @folder, "~~~"; @folder = grep /./, map { (index($folder[$_+1], "$folder[$_]\\") == 0) ? '' : $f +older[$_] } ( 0..$npaths );

    That is, sort the array and eliminate an element if it is fully contained as an initial substring of the next element. (The standard string sort will always put "a1" before "a1\1".)

    Note that I added a bogus element on the array, to avoid an "undefined value" warning when map reaches the last directory. It's not elegant, alas...

Re: Array Normalization of File::DirWalk
by jdporter (Canon) on Feb 23, 2007 at 12:26 UTC

    I'm sorry to say it, but File::DirWalk is not a very well written module. To do what you want to do properly, you have to reach into the object, breaking its encapsulation. (Hey, at least it's possible. :-) And the module's documentation is poor, in that it does not tell you what the depth parameter is really for or how it's used.

    The following works:

    for my $directory ( @directory ) { my $dw = new File::DirWalk; $dw->onDirLeave( sub{ my $dir = shift; if ( $dw->{'depth_count'} == $depth ) { push @folder, $dir; } return File::DirWalk::SUCCESS; } ); $dw->setDepth( $depth + 1 ); $dw->walk( $directory ); }

    Note two things:

    1. The test of the object's data member 'depth_count' against $depth;
    2. passing $depth + 1 to the setDepth method.

    Just for fun, here's how I'd probably write the above:

    my $dw = new File::DirWalk; sub on_dir_leave { $dw->{'depth_count'} == $depth and push @folder, shift; File::DirWalk::SUCCESS } $dw->onDirLeave( \&on_dir_leave ); $dw->setDepth( $depth + 1 ); $dw->walk( $_ ) for @directory;
    A word spoken in Mind will reach its own level, in the objective world, by its own weight
Re: Array Normalization of File::DirWalk
by Khen1950fx (Canon) on Feb 23, 2007 at 10:15 UTC
    For depth 3, I tried this, using /usr/local/lib:

    #!/usr/bin/perl use strict; use warnings; use diagnostics; use File::DirWalk; my $dir = '/usr/local/lib'; my $dw = new File::DirWalk; $dw->onDirEnter(sub { my ($dir) = @_; print "$dir\n"; return File::DirWalk::SUCCESS; }); $dw->setDepth(3); $dw->walk($dir);