这一篇是搬过来的,原来的在这儿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