我正在使用Perl的File :: Find模块来扫描文件,目录和链接。除此之外,我希望我正在编写的实用程序报告已损坏(悬挂在File :: Find的用语中)符号链接。理论上,这可以通过创建一个子程序来支持,只要找到一个断开的链接,并使用适当值的哈希引用调用find
方法,例如:
my %options = (
wanted => \&ProcessFile,
follow => 1,
follow_skip => 2,
dangling_symlinks => \&Dangling
);
find(\%options, @ARGV);
尽管故意创建一个断开的链接来测试它,但File :: Find永远不会调用子例程Dangling
。除此功能外,其他所有功能都有效,即ProcessFile
子按预期调用,跟踪链接等。
答案 0 :(得分:2)
在我的主目录中创建test.pl
:
#!/usr/bin/perl
use File::Find;
my %options = ( wanted => \&ProcessFile,
follow => 1,
follow_skip => 2,
dangling_symlinks => \&Dangling );
find(\%options, @ARGV);
sub ProcessFile {
print "ProcessFile ($File::Find::name in $File::Find::dir)\n";
}
sub Dangling {
my ($name, $dir) = @_;
print "Dangling ($name in $dir)\n";
}
然后:
$ chmod 755 test.pl $ mkdir /tmp/findtest $ cd /tmp/findtest $ ln -s /tmp/doesnotexist linkylink $ ~/test.pl .
结果:
ProcessFile (. in .) Dangling (linkylink in ./) ProcessFile (./linkylink in .)
答案 1 :(得分:2)
我做了一个快速测试来弄清楚悬挂式符号链接表现出什么样的行为,结果证明符号链接的定义是我能想到的
因此,使用File :: Find :: Rule您似乎想要做的事情相对简单:
#!/usr/bin/perl
use strict;
use warnings;
use File::Find::Rule ();
my @files = File::Find::Rule->symlink->exec(sub{ !-e $_ })->in('/tmp/test');
print "$_,\n" for @files;
此代码段能够检测到我能辨认出的所有已损坏的符号链接。
如果你想要测试我跑完了这个:
#!/usr/bin/perl
use strict;
use warnings;
use File::Path ();
use Carp ();
my $testdir = "/tmp/test";
# Generating test
# Making Dirs
dirmk($_)
for (
qw(
/realdir/
/deleteddir/
)
);
#"Touching" some files
generate($_)
for (
qw(
/realfile
/deletedfile
/realdir/realfile
/realdir/deletedfile
/deleteddir/afile
)
);
# Symlink them
{
lns( '/realfile', '/realfile_symlink' );
lns( '/deletedfile', '/deletedfile_symlink' );
lns( '/realdir', '/realdir_symlink' );
lns( '/deleteddir', '/deleteddir_symlink' );
lns( '/realdir/realfile', '/realdir_realfile_symlink' );
lns( '/realdir/deletedfile', '/realdir_deletedfile_symlink' );
lns( '/deleteddir/afile', '/deleteddir_file' );
}
# Make the deletions
del($_)
for (
qw(
/deletedfile
/deleteddir/afile
/realdir/deletedfile
/deleteddir/
)
);
statify($_)
for (
'', qw(
/realfile
/realfile_symlink
/deletedfile_symlink
/realdir
/realdir_symlink
/deleteddir_symlink
/realdir/realfile
/realdir_realfile_symlink
/realdir_deletedfile_symlink
/deleteddir_file
)
);
sub statify {
my $fn = $testdir . shift;
printf(
"r: %3s e: %3s s: %3s f: %3s d: %3s l: %3s | %s \n",
-r $fn || 0,
-e $fn || 0,
-s $fn || 0,
-f $fn || 0,
-d $fn || 0,
-l $fn || 0,
$fn
);
}
sub generate {
my $fn = $testdir . shift;
open my $fh, '>', $fn or Carp::croak("Error Creating $fn $! $@");
print $fh "This is $fn \n";
close $fh or Carp::carp("Error on close for $fn $! $@");
return;
}
sub lns {
my $x = $testdir . shift;
my $y = $testdir . shift;
if ( -e $y ) {
unlink $y;
}
symlink $x, $y or Carp::croak("Error ln $x => $y , $! $@");
}
sub del {
my $fn = $testdir . shift;
if ( -f $fn ) {
unlink $fn;
}
if ( -d $fn ) {
rmdir $fn;
}
}
sub dirmk {
my $fn = $testdir . shift;
File::Path::mkpath($fn);
}
这是输出:
r: 1 e: 1 s: 220 f: 0 d: 1 l: 0 | /tmp/test r: 1 e: 1 s: 28 f: 1 d: 0 l: 0 | /tmp/test/realfile r: 1 e: 1 s: 28 f: 1 d: 0 l: 1 | /tmp/test/realfile_symlink r: 0 e: 0 s: 0 f: 0 d: 0 l: 1 | /tmp/test/deletedfile_symlink r: 1 e: 1 s: 60 f: 0 d: 1 l: 0 | /tmp/test/realdir r: 1 e: 1 s: 60 f: 0 d: 1 l: 1 | /tmp/test/realdir_symlink r: 0 e: 0 s: 0 f: 0 d: 0 l: 1 | /tmp/test/deleteddir_symlink r: 1 e: 1 s: 36 f: 1 d: 0 l: 0 | /tmp/test/realdir/realfile r: 1 e: 1 s: 36 f: 1 d: 0 l: 1 | /tmp/test/realdir_realfile_symlink r: 0 e: 0 s: 0 f: 0 d: 0 l: 1 | /tmp/test/realdir_deletedfile_symlink r: 0 e: 0 s: 0 f: 0 d: 0 l: 1 | /tmp/test/deleteddir_file
答案 2 :(得分:1)
我喜欢看到File::Find::Rule
正在使用中,但这里没有任何区别。
话虽如此,
$ mkdir test
$ cd test
$ ln -s a b
$ perl -w -MFile::Find -e'find({wanted=>sub{print"wanted $_\n"},dangling_symlinks=>sub{print"dangling $_[0] in $_\n"},follow=>1},".")'
wanted .
dangling b in .
wanted b
适合我。
什么是perl -MFile::Find -e'print"$File::Find::VERSION\n"'
?
通过Perl的RT,我找到了#28929: File::Find follow_fast => 1 loses dangling symlink。它显然会影响File::Find
1.07及更早版本,它与Perl 5.8.7及更早版本(以及5.9.x开发行中的5.9.1及更早版本)捆绑在一起。
我建议您说服您的系统管理员更新Perl或至少几个模块(并在他们使用时添加File::Find::Rule
),但如果失败,您可以制作自己的$PERL5LIB
并在那里放置更新的模块。