perl处理链接文件
2022-02-24 18:38:36 阿炯

关于链接文件

在Unix下,硬链接与软链接(SoftLinks)两种,一种被称为硬链接(HardLink),另一种被称为符号链接(Symbolic Link)。默认情况下,ln命令产生硬链接,软链接的使用方法:ln -s TARGET or ln -s TARGET LINK

本文盘点了一些使用Perl处理链接文件的方法与示例,在Linux上实践通过,链接相关的函数有:link、readlink、symlink。另外还有一个unlink函数,它与链接没有直接关系,它与rm指令作用相近,但字面意义却很类似:解除链接或将链接数置为0,即删除文件。

1、创建软链接(linkcreate1)

use v5.16;
#22-02-23,for symlink:symbolic links(soft link)
INIT{
    my $symlink_exists = eval { symlink("",""); 1 };
    say "SymLink is OK and my pid:$$,let\'s go." if($symlink_exists);
}

my $sf=shift or die "Source File Args Not Gived!";
unless(-e $sf){
    warn "Source File:$sf Not Exist!";
}else{
    say "File:$sf is ok,let\'s go.";
    symlink($sf,"$$.txt");
};

perl linkcreate1.pl freeoa.net

2、创建硬链接(linkcreate2)

use v5.16;
#22-02-23,for link(hard link)
INIT{
    say "Link is OK and my pid:$$,let\'s go.";
}

my $sf=shift or die "Source File Args Not Gived!";
unless(-e $sf){
    warn "Source File:$sf Not Exist!";
    exit;
}else{
    say "File:$sf is ok,let's go."
};

say "Link create OK." if(link($sf,"$$.txt"));

perl linkcreate2.pl freeoa.net

3、列出相关链接文件信息

在/tmp目录下创建了如下的软链接,为了测试方便有同目录链接,相、绝对路径文件,'cyrj'为到目录的链接,来将这些文件列出:

use v5.16;
my $dir = shift or die "Usage: $0 DIR\n";
opendir my $dh,$dir or die;
for my $thing (readdir $dh){
    next if($thing eq '.' or $thing eq '..');
    print $thing;
    my $target=readlink "$dir/$thing";
  if($target){
        print "-->$target";
  }
    print "\n";
}

...
numeric.httpdweb.cap-->webserver.pcap
zhuye.zip-->/zhuye.zip
nghtml.gz-->/apps/nginx/html.zip
ssh85.tgz-->../apps/soft/ssh85.tar.gz
cyrj-->/apps/soft/

对链接文件列出其原文件完整的路径

use v5.16;
use Data::Dumper;
use Cwd qw(abs_path chdir);

my $dir = shift or die "Usage: $0 DIR\n";
#(-d $dir)?chdir($dir):exit(40);
(-d $dir)?chdir($dir):die "Dir:$dir something wrong?";
opendir my $dh,$dir or die "Open Dir:$dir Failed!";

for my $thing (readdir $dh){
    next if($thing eq '.' or $thing eq '..');
    print $thing;
    my $target=readlink "$dir/$thing";
    #say Dumper($target);
    if($target){
        print "-->".abs_path($target);
    }
    print "\n";
}

...
numeric.httpdweb.cap-->/tmp/webserver.pcap
zhuye.zip-->/zhuye.zip
nghtml.gz-->/apps/nginx/html.zip
ssh85.tgz-->/apps/soft/ssh85.tar.gz
cyrj-->/apps/soft

注意:要使用chdir到指定的目录下,否则使用了相对路径的链接文件不能正常显示(ssh85.tgz)。


4、对目录链接的判断(Detecting if a folder is a symbolic link)

目前看来有两种方式:(l)stat、readlink,symlink等指令函数,脚本如下:

use v5.16;
use Cwd qw(abs_path chdir);

my $fd = shift or die "Usage: $0 abs_path_of_link_file_or_dir\n";

#if(-d $fd && -l $fd){
if(-l $fd && -d $fd){
    say "Ok,$fd is link file for dir.";
}else{
    say "Sorry,maybe not dir-link for $fd...";
}

perl linkcheck4dir.pl /tmp/cyrj
Ok,/tmp/cyrj is link file for dir.

# create symbolic link
symlink("$path/$max_freeoa","$path/freeoa_cur_build") ||
die "cannot symlink $path/$max_freeoa $path/freeoa_cur_build";

# symbolic link information
if (defined($x = readlink("$path/freeoa_cur_build"))){
    print "$path/freeoa_cur_build points at '$x'\n";
}


5、找出哪些损坏了的链接(How can I detect that a symlink is broken)

There are two main relevant system calls, stat() and lstat(). The lstat() call will tell you that it is a symlink (but on other files, behaves the same as stat()). This allows you to determine that the name is a symlink. The stat() system call follows a symlink to its end, and tells you about the file (or directory) at the end of the link. If the stat() call fails on the symlink, then the symlink is broken or you're trying to access a directory or file where you have no permission.

The Perl file test operators include -l to detect whether a name is a symlink. You can use the Perl functions stat and lstat explicitly. Between these, you should be able to sort out whether a symlink is broken or not - but you should probably plan to write a function to do the job.


列出某目录下的损坏链接(单行版本)
perl -E 'opendir $dh, "."; say $_ for grep { !stat $_ and lstat $_ } readdir $dh'


多行版本1

use v5.16;

my ($ddir)=('/tmp');
opendir(DIR,$ddir) or die;
chdir $ddir;

foreach my $link (readdir DIR){
  next unless(-l $link and not -e readlink($link));
  print "Founding broken link $link\n";
  #unlink $link;
}

closedir DIR;

多行版本2

use v5.16;

my ($ddir)=('/tmp');
chdir($ddir) if(-e $ddir);
opendir my $dirh, $ddir;

while (my $file = readdir $dirh){
    if( -l $file ){
        my $target = readlink $file;
        if( ! -e $target && ! -l $target ){
            print "$file -> $target broken\n";
        }
    }
}

6、移除链接文件

if(-l "$freeoa/link"){
    unlink "$freeoa/link"
    or die "Failed to remove file $freeoa/link: $!\n";
}


Respective operating systems have its own errno.h. Use Errno.pm to handle each errors.

use Errno;
use File::Spec;
my $dir = File::Spec->catfile($ENV{MYHOME}, 'link');
if (!unlink $dir) {
    if ($! == Errno::ENOENT) {
        die "Failed to remove '$dir'. File doesn't exist:$!";
    }
}



参考来源:
13.3. Links and Files