2010-05-19 45 views
3

嘿,我想知道如何讓這段代碼工作。基本上我想保留$filename行,只要它們包含在路徑中$user如何從Perl數組中提取我想要的元素?

 open STDERR, ">/dev/null"; 
     $filename=`find -H /home | grep $file`; 
     @filenames = split(/\n/, $filename); 
     for $i (@filenames) { 
      if ($i =~ m/$user/) { 
       #keep results 
      } else { 
       delete $i; # does not work.  
      } 
     } 
     $filename = join ("\n", @filenames); 
     close STDERR; 

我知道你可以刪除喜歡delete $array[index]但我沒有用這種循環的,我知道一個索引的。

回答

10

您可以用替換你的循環:

@filenames = grep /$user/, @filenames; 
3

有沒有辦法當你使用foreach循環來做到這一點。但是不要緊。正確的做法是使用File::Find完成您的任務。

use File::Find 'find'; 

... 

my @files; 
my $wanted = sub { 
    return unless /\Q$file/ && /\Q$user/; 
    push @files, $_; 
}; 

find({ wanted => $wanted, no_chdir => 1 }, '/home'); 

不要忘了\Q逃避你的變量在正則表達式中使用。

BTW,您重定向到STDERR是/dev/null更好地寫成

{ 
    local *STDERR; 
    open STDERR, '>', '/dev/null'; 
    ... 
} 

它恢復退出塊後的文件句柄。

+0

謝謝,添加了本地STDERR參考。 – Flamewires 2010-05-19 20:15:33

2

如果您有一個支持-pathfind,請使其爲您完成工作,例如

#! /usr/bin/perl 

use warnings; 
use strict; 

my $user = "gbacon"; 
my $file = "bash"; 

my $path = join " -a " => map "-path '*$_*'", $user, $file; 
chomp(my @filenames = `find -H /home $path 2>/dev/null`); 

print map "$_\n", @filenames; 

注意在列表上下文反引號如何回饋線路(包括其終止,上面chomp刪除)從命令的輸出列表。這節省了你自己的split

輸出:

/home/gbacon/.bash_history 
/home/gbacon/.bashrc 
/home/gbacon/.bash_logout
+0

你能解釋一下我的$路徑行嗎?對不起,有點小菜。 – Flamewires 2010-05-19 20:58:55

+0

沒問題!完全展開後,命令變爲'find -H/home -path'* gbacon *'-a -path'* bash *'2>/dev/null',即'/ home'下的所有包含'gbacon ''和'bash'('-a'選項意味着'和'具有'find')在其路徑中的某處。尾部的'2>/dev/null'丟棄任何錯誤輸出。 – 2010-05-20 02:54:40

2

如果你想從一個數組中刪除的項,請使用多才多藝splice功能。

my @foo = qw(a b c d e f); 

splice(@foo, 3, 1); # Remove element at index 3. 

你可以用splice做各種其他操作。有關更多信息,請參閱perldoc


至於codeholic暗示,你應該永遠修改數組在遍歷其與for循環。如果您想在迭代時修改數組,請改用while循環。

原因是for一次評估parens中的表達式,並將結果列表中的每個項目映射到一個別名。如果數組發生變化,指針會變得混亂,隨後會出現混亂。

A while每次通過循環評估條件,因此您不會遇到指向不存在的值的指針問題。

+0

啊,好吧,無論如何用這個循環來試試它似乎很尷尬。 – Flamewires 2010-05-19 20:18:24