如何使用perl中的grep从一个数组中选择元素到另一个数组?

mil*_*bos 1 arrays perl grep text-processing

我想捕获 中的文件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 
Run Code Online (Sandbox Code Playgroud)

现在当前目录有这个文件:

$ls
a.txt  e.txt  getopt.html
Run Code Online (Sandbox Code Playgroud)

使用这个表达式push @files, ("foo.txt", "bar.txt"); ,数组有这些元素:("foo.txt", "bar.txt", "a.txt", "e.txt", "getopt.html"),这是正确的,但现在我只想选择那些不在CWD: 中的文件 @difference=grep { !/^\./ and $i!=$_ } readdir CWD;,所以我希望数组@difference再次("foo.txt", "bar.txt")只有(我现在这没有意义,它是例如)。但是打印出来什么都不输出,怎么回事?

Dad*_*ada 5

您的代码有很多问题:

  • 您的第二个readdir(在for my $i (@files)循环中)没有读取任何内容,因为第一个 ( @files=grep{!/^\./}readdir CWD;) 已经读取了整个目录。您可以rewinddir先使用,但简单地使用@files(在推送foo.txt和之前bar.txt)的副本会更简单、更有效。

  • 您正在使用!=而不是ne比较字符串。

  • 循环的每次迭代都会擦除之前的值,@differences因为您用=. 想必push会更有意义。

  • 循环内部的逻辑有点缺陷。grep返回满足条件的元素,但您更感兴趣的是是否有任何元素满足它。

  • 您应该检查是否opendir成功(通过添加or die ...opendir线)。另请注意,这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
Run Code Online (Sandbox Code Playgroud)

然而,这远非有效,而且比它需要的更复杂。我建议改为:

my %files = map { $_ => 1 } grep {!/^\./} readdir $CWD;

my @difference;
for ("foo.txt", "bar.txt") {
    push @difference, $_ if ! exists $files{$_};
}
print "$_\n" for @difference
Run Code Online (Sandbox Code Playgroud)

请注意,我已添加use strict; use warnings;到脚本中。始终将它们添加到您的代码中。虽然在这种特定情况下,它不会帮助您找出问题所在,但它会在未来为您节省无数时间。此外,始终使用词法文件/目录句柄(即,使用 doopendir my $CWD, "dir"而不是open CWD, "dir")。