Мой ответ с решением на чистом Perl.
С этой песочницей:
$ tree -F Volumes/
Volumes/
└── My\ HD/
├── Users/
│ └── Jim/
│ └── dev/
│ └── github/
│ └── twonky/
│ └── i_there.txt
├── dev/
├── net/
├── start.bat
└── system/
└── hello
9 directories, 3 files
Следующий код Perl, использующийFile::Find
:
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use File::Find;
my $start = 'Volumes/My HD';
my $start_dev = (stat($start))[0];
my @exclude = qw/net dev system/;
my %skipdir;
sub wanted {
my $name = $_;
return if (stat($name))[0] != $start_dev;
$skipdir{$File::Find::name} = 1 if $File::Find::dir eq $start && grep { $name eq $_ } @exclude;
if (exists($skipdir{$File::Find::dir})) {
$skipdir{$File::Find::name} = 1 if -d $name;
return;
}
return if ! -f $name;
say "Got: $File::Find::name";
}
my %args = (
wanted => \&wanted,
follow => 1,
follow_skip => 1,
);
find(\%args, $start);
дает ожидаемое (, если я вас правильно понял):
Got: Volumes/My HD/start.bat
Got: Volumes/My HD/Users/Jim/dev/github/twonky/i_there.txt
Это POC, его можно улучшить.
Обратите также внимание на то, что у вас есть find2perl
инструмент, который задокументирован, чтобы иметь возможность преобразовывать конкретный find
вызов в ассоциированный код Perl, используя File::Find
с теми же критериями.
Теперь с Path::Class
код может показаться проще/легче читать (для того же результата):
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use Path::Class;
my $start = Path::Class::Dir->new('Volumes/My HD');
my @exclude = qw/net dev system/;
$start->recurse(callback => sub {
my $node = shift;
if ($node->is_dir) {
return $node->PRUNE if $node->parent eq $start && grep { $node->dir_list(-1) eq $_ } @exclude;
return;
}
return $node->PRUNE if $node->stat()->dev != $start->stat()->dev;
say 'Got: ', $node->stringify();
}, preorder => 1)