沒看完_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\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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM