如何使用 perl 中的 grep select 元素从一个数组到另一个数组?
how to select elements from one array to another with grep in perl?
我想捕捉 CWD
中的文件与 @files
中的文件之间的差异:
#!/usr/bin/perl -w
use Cwd qw[getcwd abs_path];
opendir CWD, getcwd;
@files=grep{!/^\./}readdir CWD;
push @files, ("foo.txt", "bar.txt");
for my $i (@files){
@difference=grep { !/^\./ and $i!=$_ } readdir CWD;
}
print "$_\n" for @differenc
现在当前目录有这些文件:
$ls
a.txt e.txt getopt.html
用这个表达式push @files, ("foo.txt", "bar.txt");
该数组具有这些元素:("foo.txt", "bar.txt", "a.txt", "e.txt", "getopt.html")
,这是正确的,但现在我只想 select 那些文件,这些文件在 CWD 中是 而不是 :
@difference=grep { !/^\./ and $i!=$_ } readdir CWD;
,所以我期望数组 @difference
再次只有 ("foo.txt", "bar.txt")
(我现在这没有任何意义,只是为了举例)。但是打印什么也没有输出,怎么回事?
您对同一个文件句柄有两个 readdir
操作。一旦第一个到达 EOF,就不再返回任何内容。
在第二次迭代之前添加一个`rewinddir操作。
您的代码有很多问题:
您的第二个 readdir
(在 for my $i (@files)
循环中)没有读取任何内容,因为第一个 (@files=grep{!/^\./}readdir CWD;
) 已经读取了整个目录。您可以先使用 rewinddir
,但仅使用 @files
的副本(在推送 foo.txt
和 bar.txt
之前)会更简单、更有效。
您正在使用 !=
而不是 ne
来比较字符串。
循环的每次迭代都会删除 @differences
的先前值,因为您使用 =
为它赋值。大概 push
会更有意义。
循环中的逻辑有点缺陷。 grep
returns满足条件的元素,但你更感兴趣的是是否有元素满足
您应该检查 opendir
是否成功(通过向 opendir
行添加 or die ...
)。另外,请注意 open my $CWD, getcwd
等同于更简单的 open my $CWD, "."
.
您可能想要做的是:
use strict;
use warnings;
opendir my $CWD, "." or die "Could not open '.': $!";
my @files = grep{!/^\./} readdir $CWD;
my @init_files = @files;
push @files, ("foo.txt", "bar.txt");
my @difference;
for my $i (@files){
push @difference, (grep { !/^\./ and $i eq $_ } @init_files) ? () : $i;
}
print "$_\n" for @difference
然而,这远非高效,而且比需要的更复杂。我建议改为:
my %files = map { $_ => 1 } grep {!/^\./} readdir $CWD;
my @difference;
for ("foo.txt", "bar.txt") {
push @difference, $_ if ! exists $files{$_};
}
print "$_\n" for @difference
请注意,我已将 use strict; use warnings;
添加到脚本中。始终将它们添加到您的代码中。虽然在那种特定情况下,它不会帮助您找出问题所在,但它会在未来为您节省无数小时。此外,始终使用词法 file/directory 句柄(即 opendir my $CWD, "dir"
而不是 open CWD, "dir"
)。
我想捕捉 CWD
中的文件与 @files
中的文件之间的差异:
#!/usr/bin/perl -w
use Cwd qw[getcwd abs_path];
opendir CWD, getcwd;
@files=grep{!/^\./}readdir CWD;
push @files, ("foo.txt", "bar.txt");
for my $i (@files){
@difference=grep { !/^\./ and $i!=$_ } readdir CWD;
}
print "$_\n" for @differenc
现在当前目录有这些文件:
$ls
a.txt e.txt getopt.html
用这个表达式push @files, ("foo.txt", "bar.txt");
该数组具有这些元素:("foo.txt", "bar.txt", "a.txt", "e.txt", "getopt.html")
,这是正确的,但现在我只想 select 那些文件,这些文件在 CWD 中是 而不是 :
@difference=grep { !/^\./ and $i!=$_ } readdir CWD;
,所以我期望数组 @difference
再次只有 ("foo.txt", "bar.txt")
(我现在这没有任何意义,只是为了举例)。但是打印什么也没有输出,怎么回事?
您对同一个文件句柄有两个 readdir
操作。一旦第一个到达 EOF,就不再返回任何内容。
在第二次迭代之前添加一个`rewinddir操作。
您的代码有很多问题:
您的第二个
readdir
(在for my $i (@files)
循环中)没有读取任何内容,因为第一个 (@files=grep{!/^\./}readdir CWD;
) 已经读取了整个目录。您可以先使用rewinddir
,但仅使用@files
的副本(在推送foo.txt
和bar.txt
之前)会更简单、更有效。您正在使用
!=
而不是ne
来比较字符串。循环的每次迭代都会删除
@differences
的先前值,因为您使用=
为它赋值。大概push
会更有意义。循环中的逻辑有点缺陷。
grep
returns满足条件的元素,但你更感兴趣的是是否有元素满足您应该检查
opendir
是否成功(通过向opendir
行添加or die ...
)。另外,请注意open my $CWD, getcwd
等同于更简单的open my $CWD, "."
.
您可能想要做的是:
use strict;
use warnings;
opendir my $CWD, "." or die "Could not open '.': $!";
my @files = grep{!/^\./} readdir $CWD;
my @init_files = @files;
push @files, ("foo.txt", "bar.txt");
my @difference;
for my $i (@files){
push @difference, (grep { !/^\./ and $i eq $_ } @init_files) ? () : $i;
}
print "$_\n" for @difference
然而,这远非高效,而且比需要的更复杂。我建议改为:
my %files = map { $_ => 1 } grep {!/^\./} readdir $CWD;
my @difference;
for ("foo.txt", "bar.txt") {
push @difference, $_ if ! exists $files{$_};
}
print "$_\n" for @difference
请注意,我已将 use strict; use warnings;
添加到脚本中。始终将它们添加到您的代码中。虽然在那种特定情况下,它不会帮助您找出问题所在,但它会在未来为您节省无数小时。此外,始终使用词法 file/directory 句柄(即 opendir my $CWD, "dir"
而不是 open CWD, "dir"
)。