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

问题描述 投票:0回答:4

嘿,我想知道如何让这段代码工作。基本上我想保留

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

arrays regex perl
4个回答
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
转义变量以便在正则表达式中使用。

顺便说一句,将 STDERR 重定向到

/dev/null
更好地写成

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

退出块后恢复文件句柄。


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

2
投票

如果您想从数组中删除项目,请使用多才多艺的

splice
函数。

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

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

您可以使用

splice
进行各种其他操作。请参阅 perldoc 了解更多信息。


正如代码狂所暗示的那样,您应该永远在使用

for
循环迭代数组时修改数组。如果您想在迭代时修改数组,请使用
while
循环。

这样做的原因是

for
对括号中的表达式求值一次,并将结果列表中的每个项目映射到一个别名。如果数组发生变化,指针就会出错,混乱就会随之而来。

A

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

© www.soinside.com 2019 - 2024. All rights reserved.