• 没看完_perl的find模块很全面的讲解!!


    这一篇是搬过来的,原来的在这儿http://www.freeoa.net/development/perl/perl-mod-file-find_2114.html

    尊重他人劳动成果,感谢!


    它是Perl核心模块之一,用于文件的搜索及查找。Perl之中的File::Find模块对在整个文件系统中搜索文件名十分有用,特别是你可以使用正则来匹配文件名并循环地穿过任何的目录结构(许可情况下)。为了展示它的工作方式,我将给出一个使用File::Find模块的脚本实例。

    语法:
     use File::Find;
     find(&wanted, @directories_to_search);
     sub wanted { ... }

     use File::Find;
     find({ wanted => &process, follow => 1 }, '.');

    File::Find的两个方法:
    find 是自上而下遍历。

    finddepth 是自下而上遍历。
    二者调用格式相同,上例中 finddepth(&del_svn, "."),第一个参数是调用的子函数,第二个参数是根目录。

    这里简单的说一下 find 函数,find 函数的用法如下:
    find(&wanted, @directories_to_search);

    find()函数包含两个参数,子程序的引用和目录列表。第一个参数是一个代码的引用或者是一个hash引用对于每个文件。

    其中第一个参数 wanted 是个子函数,也就是回调函数,由你自己来定义,这个参数必须有,即使它的内容为空。第二个参数是个目录列表,一般情况下,我们可能只是处理一个目录,所以它也可以是个普通的表示目录名的字串标量。

    需要注意的是,&wanted 子程序的前面需要加一反斜杠转义。

    与文件及其路径相关的三个属性:
    $File::Find::dir 是当前目录全路径。
    $_ 是当前文件名(不含路径)。
    $File::Find::name 是当前文件的完整路径。

    $File::Find::dir is the current directory name,
    $_ is the current filename within that directory
    $File::Find::name is the complete pathname to the file.

     以文件'/some/path/foo.ext '为例:
    $File::Find::dir  = /some/path/
    $_  = foo.ext
    $File::Find::name = /some/path/foo.ext

    File::Find的属性
    在使用过程中,可以设置其具体属性来改变其行为,最终得到想要结果。
    find(\%options, @directories);

    finddepth(\%options, @directories);

    其实上面所提及的wanted函数,就是这个%options中的最重要的key了。

    Perl脚本可以寻找以.tmp, .chk或是.zip结尾的文件或是以~符号开始的文件来完成,脚本将输出它找到的每一个文件的完整路径,而且在最后会显示出所占用的字节数。

    在标准Perl库和Perl函数中设置了一个模块,因此当你的机器上安装了Perl之后,所有必要的模块就都可以使用了,File::Find函数模仿了UNIX的find命令并将穿过一个文件树。这里是此方式的API: 
    Find(&yoursubroutine, ‘dir1’, ‘dir2’…); 

    提供的子程序,将在后面详细叙述,还有希望进行搜索的目录的列表,记住这些目录将以一种深度优先方式被穿过,使用的另一个方式就是stat()函数(与C的同名库函数类似)。

    File::Find方式具有特殊变量,将被赋予特定的信息,显示如下: 
    * $_包含目录中的当前文件名 
    * $File::Find::dir包含当前目录名 
    * $File::Find::name包含$File::Find::dir/$_ 

    当子程序被调用时,就会确实位于变量$File::Find::dir的目录中,子程序使用常规表达式来与$_匹配,$_使用一个if声明来寻找我们前面详细给出的所有文件名。 

    如果在$_之中存储的文件名与if声明中的五个常规表达式中的任何一个相匹配,我们就将在其下面输入代码块,常规表达式非常的简单,“.”代表一个文字上的点号而不是常规表达式中的“.”的特殊意义,我们使用“”符号来避开特殊意义。“$”代表一个字符串最后的匹配而“^”代表与开头匹配。下表显示了我们试图将其与相对应的常规表达式相匹配的文件。 
    File that ends with .zip     /.zip$/ 
    File that ends with .tmp     /.tmp$/ 
    File that ends with .TMP     /.TMP$/ 
    File that begins with ~     /^~/ 
    File that ends with .chk     /.chk/ 

    注意:脚本对小写的tmp和大写的TMP同时进行查找,而出于效率方面的考虑,可以将文件名改为大写并只查找TMP匹配。 

    最后,脚本使用stat()函数来记录所有与if声明之中的某个条件相匹配的文件所使用的字节数。如果条件符合,脚本将存储$size之中的值并将其加入到$ByteCount记录变量,如下面的代码所示: 
    $ByteCount += $size; 

    perl下的File::Find模块具有shell下的find命令的功能,下面具体看2个例子: 

    1、找出某个目录下面以*.old结尾的文件 
    use strict; 
    use File::Find; 
    my $path = '/home/test/'; 
    sub wanted { 
    if ( -f $File::Find::name ) { 
     if ( $File::Find::name =~ /.old$/ ) { 
      print "$File::Find::name "; 
      }
     }
    }
    find( &wanted, $path ); 

    2、找出某个目录下面几天前的文件 
    my $path = '/home/test/'; 
    opendir DH, $path or die "cannot chdir to $path : $!"; 
    for my $file (readdir DH) { 
     next if $file eq "." or $file eq ".."; 
     next if $file =~ /^./; 
     if (time() - (stat($path.$file))[8] > (60*60*24*7)) { 
      print $path.$file." "; 
     } 

    closedir DH;

    Perl中的find模块使用方式有以下几种:
    use File::Find; 
    find(/&wanted, @directories_to_search); 
    sub wanted { ... } 

    use File::Find; 
    finddepth(/&wanted, @directories_to_search); 
    sub wanted { ... } 

    use File::Find; 
    find({ wanted => /&process, follow => 1 }, '.'); 

    主要有两个函数,find和finddepth,这两个方法大致相同,但也有细微的差别: 
    find: 
    find(/&wanted,  @directories); 
    find(/%options, @directories); 
    find()会在@directories的参数所给定的目录中顺序的进行深度优先的查找,对于每一个找到的 文件 或者目录,都会调用&wanted引用所指向的sub(函数)。$wanted函数的具体使用见下文。 

    另外,对于每一个找到的目录,它都会chdir()到这个目录内部,然后递归的在这个目录中 继续调用&wanted sub来操作这个目录下的子目录或文件。 

    finddepth: 
    finddepth(/&wanted,  @directories); 
    finddepth(/%options, @directories); 

    finddepth()函数的用法和find()几乎一样,只不过它会在查找完当前目录之后 ,再进入当前 目录的子目录中进行查找。它采用了后序遍历算法取代了前序遍历算法。 

    wanted函数: 
    在wanted()函数中,可以对文件和目录做任何形式的判断和确认。需要注意的是:wanted() 函数实质上是一个回调函数,它的返回值被忽略。 wanted函数没有参数,但是会包含一系列的内部变量,如: 
    $File::Find::dir     是当前目录的名字 
    $_     是当前正在处理的文件名 
    $File::Find::name     是当前文件的完整路径+文件名 

    以上变量都已经被包含在wanted函数中,并且不会影响函数外的同名变量。 例如,如果要检查文件 
    /some/path/foo.ext 
    ,这些变量的值就是: 
    $File::Find::dir  = /some/path/ 
    $_                = foo.ext 
    $File::Find::name = /some/path/foo.ext 

    程序运行时将会chdir()到$File::Find::dir目录中,除非没有子目录了。 

    程序示例: 
    sub wanted { 
    /^/.nfs.*/z/s && 
    (($dev, $ino, $mode, $nlink, $uid, $gid) = lstat($_)) && 
    int(-M _) > 7 && 
    unlink($_) 
    || 
    ($nlink || (($dev, $ino, $mode, $nlink, $uid, $gid) = lstat($_))) && 
    $dev < 0 && 
    ($File::Find::prune = 1); 
    }

    比较重要的参数有:wanted、bydepth、no_chdir

    wanted
    它将指向一代码块,其中包含了对每一个找到的'项'和处理逻辑。

    bydepth
    在将目录符合条件文件列表输出后,再输出该目录名。

    no_chdir
    当置为'false'时,在其工作过程中,不进入(chdir)其所在的当前目录。下面是其默认、false、true三种情况的对比:
                 $File::Find::name  $File::Find::dir  $_
     default      /                  /                 .
     
     no_chdir=>0  /etc               /                 etc
                  /etc/x             /etc              x

     no_chdir=>1  /                  /                 /
                  /etc               /                 /etc
                  /etc/x             /etc              /etc/x

    $find::Find::prune 可停止将find()函数移到该目录中
    use File::Find;
    find(&wanted,'/root/bin');
    sub wanted{
     #停止搜索sys目录
     $File::Find::prune = 1 if /sys/;
     if (/.log/i) {
      print "FILE: $_ ";
      print "Dir: $File::Find::dir ";
      print "Path: $File::Find::name ";
     }
    }

    参考文档:
    File::Find

  • 相关阅读:
    搭建一个简单的springMVC框架
    java枚举使用
    java中枚举类型的使用
    java递归算法
    JAVA递归算法及经典递归例子 对于这个汉诺塔问题
    java斐波纳契数列
    要求给一个数值,计算它的阶乘
    AcWing2193 分配问题(二分图最优匹配)
    2020上海大学校赛L 动物森友会(网络流+二分)
    BZOJ2654 tree(wqs二分)
  • 原文地址:https://www.cnblogs.com/xf666/p/7003610.html
Copyright © 2020-2023  润新知