2010-05-19 43 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