我想使用Perl删除目录中损坏的符号链接。
在我看来,我只需要列出一个目录的文件,然后测试这是一个符号链接(-l
(吗?如果它返回false,就取消它的链接。
但当使用readir列出所有文件时,我断开的符号链接似乎不会被重新组织为一个文件。因为我的链接没有指向任何东西,我明白为什么。
$myDir
中的所有文件都是符号链接,要么有效,要么已损坏。当我显示@files时,我只得到一个有效符号链接的列表。
opendir DIR, $myDir;
my @files = grep(/$regexp/,readdir(DIR));
closedir DIR;
print "filenames : @filesn";
有两个主要的相关系统调用,stat()
和lstat()
。lstat()
调用将告诉您它是一个符号链接(但在其他文件上,其行为与stat()
相同(。这允许您确定该名称是符号链接。stat()
系统调用跟随一个符号链接到达其末端,并在链接末端告诉您有关文件(或目录(的信息。如果stat()
调用在符号链接上失败,则符号链接已断开,或者您正试图访问没有权限的目录或文件。
Perl文件测试操作符包括-l
,用于检测名称是否为符号链接。您可以显式地使用Perl函数stat
和lstat
。在这两者之间,您应该能够判断符号链接是否断开,但您可能应该计划编写一个函数来完成这项工作。
您可能不需要使用readlink
Perl函数。小心底层系统readlink()
调用;它不会返回以null结尾的字符串!
有趣的是,Perl及其POSIX模块都不支持realpath()
函数。但是,PathTools模块确实支持它。如果realpath
失败,在符号链接上,符号链接将不起作用(也称为断开(。
结合lstat
和stat
:
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
以下是我用来删除断开链接的一些代码:
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 $linkn";
unlink $link;
}
closedir DIR;
请注意,包含链接的目录是当前目录,这一点很重要。readdir
只返回文件名,并且链接可能是相对的。
检查损坏的符号链接(如果存在到符号链接的符号链接,则仅检查顶层(:
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 brokenn";
}
}
}
使用readlink()
和stat()
作为结果。
使用内置的Perl glob函数?例如:
@files = <*>;
foreach $file (@files) {
print $file . "n";
}
对于特定的$dir
:
@files = <$dir*>;
foreach $file (@files) {
print $file . "n";
}
断开的符号链接是不存在的链接(-l
((!-e
(
perl -e 'print "broken: $_n" for grep { -l and ! -e } glob("*");'