嘿,我想知道如何让这段代码工作。基本上我想保留
$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]
那样删除,但我没有我所知道的这种循环的索引。
您可以将循环替换为:
@filenames = grep /$user/, @filenames;
当您使用
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';
...
}
退出块后恢复文件句柄。
如果您有支持
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
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
每次通过循环都会评估条件,因此您不会遇到指向不存在值的指针的问题。