嘿,我想知道如何让这段代码运行起来。基本上我想保留$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]
一样删除,但我没有这种循环的索引,我知道。
答案 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
每次循环都会评估条件,因此您不会遇到指向不存在的值的问题。