2013-04-05 113 views
1

我寫了一些腳本,遞歸地打印目錄的內容。但它會爲每個文件夾打印警告。如何解決這個問題?目錄樹警告

樣品夾:

dev的#坎德拉/ TMP /測試
dev的#LS -p -R
TEST2/
testfile的
testfile2

./test2:
testfile3
testfile4

我的代碼:

#!/usr/bin/perl 

use strict; 
use warnings; 

browseDir('/tmp/test'); 

sub browseDir { 
    my $path = shift; 
    opendir(my $dir, $path); 
    while (readdir($dir)) { 
     next if /^\.{1,2}$/; 
     if (-d "$path/$_") { 
      browseDir("$path/$_"); 
     } 
     print "$path/$_\n"; 
    } 
    closedir($dir); 
} 

和輸出:

開發#perl的/tmp/cotest.pl
的/ tmp /測試/測試2/testfile3
的/ tmp /測試/測試2/testfile4
使用未初始化值$ _的在 級聯(。)或串在/tmp/cotest.pl線16
/TMP /測試/
/TMP /測試/ testfile的
/TMP /測試/ testfile2

+0

'文件:: Spec' < - 這個模塊有'no_upwards()'FUNC隱藏像'.'或'..'所有目錄。例如:'@paths =文件::規格 - > no_upwards(@paths);' – gaussblurinc 2013-04-05 13:01:53

+0

你應該把一個'使用5.012;'在你的程序,因爲你用'而(READDIR($ DIR)){...}'這在早期版本中不起作用。 – 2013-04-05 14:59:29

回答

1

您可能試試這個代碼:

#!/usr/bin/perl 

    use strict; 
    use warnings; 

    browseDir('/tmp'); 

    sub browseDir { 
     my $path = shift; 
     opendir(my $dir, $path); 
     while (readdir($dir)) { 
      next if /^\.{1,2}$/; 
      print "$path/$_\n"; 
      if (-d "$path/$_") { 
       browseDir("$path/$_"); 
      } 
     } 
     closedir($dir); 
    } 

如果你有這個錯誤,那是因爲你在使用變量$ _之前調用browseDir()。

+0

謝謝,它的工作原理。另外如果我不使用$ _變量沒有警告打印。 'while(my $ s = readdir($ dir)){...}' – Suic 2013-04-05 13:02:34

+0

OP是否改變了他的代碼?我無法找到你和他的任何區別。 – ikegami 2013-04-05 13:28:58

+0

'打印 「$ PATH/$ _ \ n」;'上升 – Suic 2013-04-05 13:35:35

1

你放在$_值調用browseDir之前,你希望它的價值是調用browseDir(一個合理的預期)後存在,但browseDir修改該變量。

只需添加local $_;browseDir以確保任何改變它的子退出之前撤消。


無關你的問題,這裏有其他的三個問題:

  • 沒有最起碼的錯誤檢查!
  • 您可能會用完目錄句柄將導航深層目錄。
  • 您過濾掉了文件".\n""..\n"

修復:

#!/usr/bin/perl 

use strict; 
use warnings; 

browseDir('/tmp/test'); 

sub browseDir { 
    my $path = shift; 

    opendir(my $dh, $path) or die $!; 
    my @files = readdir($dh); 
    closedir($dh); 

    for (@files) { 
     next if /^\.{1,2}z/; 
     if (-d "$path/$_") { 
      browseDir("$path/$_"); 
     } 

     print "$path/$_\n"; 
    } 
} 

最後,爲什麼不使用你的模塊狀File::Find::Rule

use File::Find::Rule qw(); 
print "$_\n" for File::Find::Rule->in('/tmp'); 

注:5之前。12,while (readir($dh))必須寫入while (defined($_ = readdir($dh)))

+0

感謝您的意見,我永遠不會使用$ _了^ _^ – Suic 2013-04-05 13:32:46

+0

其實'而(READDIR($ DIR)){...}'被轉換爲'而(定義($ _ = READDIR($ DIR) )){...}從[5.12]開始(http://perldoc.perl.org/perlfunc.html#readdir-DIRHANDLE)。 [提交](http://perl5.git.perl.org/perl.git/commit/114c60ecb1f775ef1deb4fdc8fb8e3a6f343d13d)不幸的是,這從來沒有成爲一個三角洲。 – 2013-04-05 15:11:29

+0

@Brad Gilbert,真的哦!那麼問題是缺少'$ _'的本地化。遞歸調用是破壞'$ _'中父對象的值。更新了答案。 – ikegami 2013-04-05 17:24:45

1

爲什麼不使用File::Find模塊?自Perl 5.x以來,它幾乎包含在Perl的所有發行版中。這不是我最喜歡的模塊,因爲它的工作方式很混亂,但它做得很好。

可以定義你想要做的是什麼wanted子程序,並過濾掉你不想要的東西。在這種情況下,您幾乎可以打印所有內容,因此所有wanted都會打印出找到的內容。

File::Find中,文件的名稱保存在$File::Find::name中,該文件的目錄在$File::Find::dir中。 $_是文件本身,可用於測試。

這裏有你想要的一個基本途徑:

use strict; 
use warnings; 
use feature qw(say); 

use File::Find; 

my $directory = `/tmp/test`; 

find (\&wanted, $directory); 

sub wanted { 
    say $File::Find::Name; 
} 

我寧願把我的wanted功能在我find子程序,所以他們在一起。這相當於以上內容:

use strict; 
use warnings; 
use feature qw(say); 

use File::Find; 

my $directory = `/tmp/test`; 

find ( 
    sub { 
     say $File::Find::Name 
    }, 
    $directory, 
); 

好的編程說不打印在子程序中。相反,您應該使用子例程來存儲和返回數據。不幸的是,find根本沒有返回任何東西。你必須使用一個全球陣列捕捉到的文件列表,後來把它們打印出來:

use strict; 
use warnings; 
use feature qw(say); 

use File::Find; 

my $directory = `/tmp/test`; 
my @directory_list; 

find ( 
    sub { 
     push @directory_list, $File::Find::Name 
    }, $directory); 

for my $file (@directory_list) { 
    say $file; 
} 

或者,如果你喜歡一個獨立的wanted子程序:

use strict; 
use warnings; 
use feature qw(say); 

use File::Find; 

my $directory = `/tmp/test`; 
my @directory_list; 

find (\&wanted, $directory); 
sub wanted { 
    push @directory_list, $File::Find::Name; 
} 

for my $file (@directory_list) { 
    say $file; 
} 

事實證明我的通緝子程序取決於數組的子程序困擾我這就是爲什麼我喜歡嵌入我的find調用內部的wanted子程序,這不是地方。

一兩件事你可以做的是使用你的子程序來篩選出你想要的東西。比方說,你在JPG文件是唯一感興趣的是:

use strict; 
use warnings; 
use feature qw(say); 

use File::Find; 

my $directory = `/tmp/test`; 
my @directory_list; 

find (\&wanted, $directory); 
sub wanted { 
    next unless /\.jpg$/i; #Skip everything that doesn't have .jpg suffix 
    push @directory_list, $File::Find::Name; 
} 

for my $file (@directory_list) { 
    say $file; 
} 

注意通緝子程序如何做之前我把它放到我@directory_list陣列我不希望任何文件next。同樣,我更喜歡嵌入:

find (sub { 
    next unless /\.jpg$/i; #Skip everything that doesn't have .jpg suffix 
    push @directory_list, $File::Find::Name; 
} 

我知道這是不是正是你問什麼,但我只是想讓你知道的Find::File模塊併爲您介紹Perl模塊(如果你沒有已經瞭解它們)可以爲Perl添加很多功能。