2011-07-05 108 views
8

我想使用Perl刪除目錄中的符號鏈接。如何檢測Perl中符號鏈接是否損壞?

在我看來,我只需要列出一個目錄的文件,並測試這是一個符號鏈接(-l),如果它返回false只是取消鏈接它。

但是,當使用readir列出所有文件時,我的破碎符號鏈接不會被識別爲文件。因爲我的鏈接沒有指向任何東西,我明白爲什麼。

然後:如何檢測符號鏈接是否在Perl中損壞?

謝謝

UPDATE

在$ MYDIR所有的文件都是符號鏈接,或是有效或折斷。 當我顯示@files時,我只會得到一個有效的符號鏈接列表。

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

你是什麼意思 「沒有recoganized爲文件」?通過什麼方式?顯示你的代碼。 – ysth

回答

8

有兩個主要的相關係統調用,stat() and lstat()lstat()調用會告訴你它是一個符號鏈接(但在其他文件上,其行爲與stat()相同)。這使您可以確定該名稱是符號鏈接。系統調用遵循一個符號鏈接,並告訴你鏈接末尾的文件(或目錄)。如果stat()調用在符號鏈接上失敗,則符號鏈接斷開或者您嘗試訪問沒有權限的目錄或文件。

Perl file test運算符包括-l來檢測名稱是否是符號鏈接。您可以明確地使用Perl函數statlstat。在這些之間,您應該能夠理清符號鏈接是否被破壞 - 但是您應該計劃編寫一個函數來完成這項工作。您可能不需要使用Perl函數readlink。當心系統readlink()調用;它不會返回以null結尾的字符串!

有趣的是,Perl及其POSIX模塊都不支持realpath()函數。但是,PathTools模塊確實支持它。如果realpath失敗,則在符號鏈接上,符號鏈接不起作用(又名破碎)。

+0

所有的答案都很棒。我只是有效的解釋這一個。謝謝。 – Spredzy

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只返回文件名,鏈接可能是相對的。

+1

+1:關於名稱相對性的好處。除了-l「$ dir/$ link」而不是-e「$ dir/$ link」',您可以將'readdir'中的值添加到目錄的名稱(相對或絕對),並從那裏開始工作:'next。我在那個重寫中省略了'readlink';我認爲這是確定的,因爲O/S爲您讀取鏈接。 –

+0

+1與@Jonathan Leffier相同,用於名稱的相對性! – Spredzy

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"; 
     } 
    } 
} 
2

使用readlink()stat()結果。

6

結合lstatstat

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

更新:我的作品......

[email protected]:~/t/dl$ perl -E 'opendir $dh, "."; say $_ for grep { !stat $_ and lstat $_ } readdir $dh' 
foo 
[email protected]:~/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 
1

使用內置的Perl的glob功能? 爲例子:

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

對於特定$dir

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