這一篇是搬過來的,原來的在這兒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\n";
}
}
}
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."\n";
}
}
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: $_\n";
print "Dir: $File::Find::dir\n";
print "Path: $File::Find::name\n";
}
}
參考文檔:
File::Find