如何检测Perl中的符号链接是否已损坏?

时间:2011-07-05 09:46:52

标签: linux perl symlink

我想使用Perl删除目录中的符号链接。

在我看来,我只需要列出一个目录的文件,测试这是一个符号链接(-l),如果它返回false则只需取消链接。

但是看起来当使用readir列出所有文件时,我的破坏的符号链接不会被识别为文件。因为我的链接指向什么,我理解为什么。

然后:如何检测Perl中的符号链接是否已损坏?

谢谢,

更新

$ myDir中的所有文件都是符号链接,有效或已损坏。 当我显示@files时,我只得到一个有效的符号链接列表。

opendir DIR, $myDir;
my @files = grep(/$regexp/,readdir(DIR));
closedir DIR;
print "filenames : @files\n";

6 个答案:

答案 0 :(得分:8)

有两个主要的相关系统调用stat() and lstat()lstat()调用将告诉您它是符号链接(但在其他文件上,其行为与stat()相同)。这允许您确定该名称是符号链接。 stat()系统调用遵循符号链接到其结尾,并告诉您链接末尾的文件(或目录)。如果符号链接上的stat()调用失败,则符号链接中断,或者您尝试访问没有权限的目录或文件。

Perl file test运算符包括-l以检测名称是否为符号链接。您可以明确使用Perl函数statlstat。在这些之间,您应该能够理清符号链接是否被破坏 - 但您应该计划编写一个函数来完成这项工作。

您可能不需要使用readlink Perl函数。注意底层系统readlink()调用;它不会返回以null结尾的字符串!

有趣的是,Perl及其POSIX模块都不支持realpath()函数。但是,PathTools模块确实支持它。如果realpath失败,则在符号链接上,符号链接无法使用(也称为已损坏)。

答案 1 :(得分:6)

lstatstat结合使用:

say "dangling link at $fn" if (lstat $fn and not stat $fn);

更新:它对我有用......

salva@topo:~/t/dl$ perl -E 'opendir $dh, "."; say $_ for grep { !stat $_ and lstat $_ } readdir $dh'
foo
salva@topo:~/t/dl$ ls -l
total 0
-rw-rw-r-- 1 salva salva  0 2011-07-05 12:34 f
lrwxrwxrwx 1 salva salva 11 2011-07-05 12:00 fii -> /etc/shadow
lrwxrwxrwx 1 salva salva 12 2011-07-05 11:59 foo -> /etc/hjdkshf

答案 2 :(得分:4)

以下是我用来删除损坏链接的一些代码:

chdir $dir        or die;
opendir(DIR, '.') or die;

foreach my $link (readdir DIR) {
  next unless -l $link and not -e readlink($link);

  print "Removing broken link $link\n";
  unlink $link;
}

closedir DIR;

请注意,包含链接的目录是当前目录非常重要。 readdir仅返回文件名,链接可能是相对的。

答案 3 :(得分:3)

检查符号链接是否损坏(如果符号链接存在符号链接,则只检查顶层):

use strict;
use warnings;
use autodie;
opendir my $dirh, '.';
while (my $file = readdir $dirh) {
    if ( -l $file ) {
        my $target = readlink $file;
        if ( ! -e $target && ! -l $target ) {
            print "$file -> $target broken\n";
        }
    }
}

答案 4 :(得分:2)

使用readlink()stat()结果。

答案 5 :(得分:1)

使用内置的Perl glob函数? 例如:

 @files = <*>;
 foreach $file (@files) {
   print $file . "\n";
 }

对于特定的$dir

 @files = <$dir*>;
 foreach $file (@files) {
   print $file . "\n";
 }