如何从Perl数组中提取出我想要的元素?

时间:2010-05-19 19:31:25

标签: arrays perl

嘿,我想知道如何让这段代码运行起来。基本上我想保留$filename的行,只要它们在路径中包含$user

        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]一样删除,但我没有这种循环的索引,我知道。

4 个答案:

答案 0 :(得分:10)

你可以用以下代码替换你的循环:

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

答案 1 :(得分: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';
    ...
}

退出块后恢复文件句柄。

答案 2 :(得分:2)

如果您的find支持-path,请让它为您完成工作,例如

#! /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

答案 3 :(得分: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中的表达式,并将结果列表中的每个项目映射到别名。如果数组发生变化,指针就会搞砸,随之而来的就是混乱。

while每次循环都会评估条件,因此您不会遇到指向不存在的值的问题。