как выбрать элементы из одного массива в другой с помощью grep в perl? - PullRequest
1 голос
/ 03 августа 2020

Я хотел бы зафиксировать разницу между файлами в 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"), что правильно, но теперь я хотел бы выбрать только те файлы, которые не в CWD: @difference=grep { !/^\./ and $i!=$_ } readdir CWD;, поэтому я ожидаю array @difference, чтобы снова было ("foo.txt", "bar.txt") (у меня теперь нет смысла, это для примера). Но на печать ничего не выводится, что не так?

Ответы [ 2 ]

5 голосов
/ 03 августа 2020

С вашим кодом довольно много проблем:

  • Второй readdirfor my $i (@files) l oop) ничего не читает с первого. (@files=grep{!/^\./}readdir CWD;) уже прочитал весь каталог. Вы можете сначала использовать rewinddir, но просто использовать копию @files (перед нажатием foo.txt и bar.txt) будет проще и эффективнее.

  • Вы используете != вместо ne для сравнения строк.

  • Каждая итерация вашего l oop стирает предыдущее значение @differences с момента его назначения с =. По-видимому, push будет иметь больше смысла.

  • Лог c внутри вашего l oop немного ошибочен. 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

Это далеко не так. однако эффективно и сложнее, чем должно быть. Вместо этого я предлагаю:

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; в сценарий. Всегда добавляйте их в свои коды. Хотя в этом конкретном случае c это не помогло бы вам выяснить, что не так, это сэкономит вам бесчисленное количество часов в будущем. Кроме того, всегда используйте лексические дескрипторы файлов / каталогов (т. Е. opendir my $CWD, "dir", а не open CWD, "dir").

1 голос
/ 03 августа 2020

У вас есть две readdir операции с одним дескриптором файла. Как только первый достигает EOF, больше нечего возвращать.

Добавьте операцию ` rewinddir перед второй итерацией.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...