如何使用 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.txtbar.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")。