Поиск имени файла с использованием регулярных выражений и глобальных переменных

#regex #perl

#регулярное выражение #perl

Вопрос:

У меня есть требование найти имя файла, отобразить текст, если он присутствует, и ниже приведен код, который я использую

 use strict;
use warnings;
use feature "say";

my @arr={"file1*.gz","file2*.gz"};
foreach my $file (@arr) {
    my $file1=glob ("$file");
    say "$file1";
    if (-e $file1) {
        say "File Generated using script";
    }
}
 

Когда я использую приведенный ниже код, я могу правильно получить 1-й элемент массива, но для 2-го элемента я вижу ошибку ниже:

 Use of uninitialized value $file1 in string
 

И если размер массива равен 1, то он работает правильно.

Я не уверен, что происходит не так в приведенном выше коде.

Ответ №1:

Существует проблема с этой строкой:

 my @arr={"file1*.gz","file2*.gz"};
 

Я думаю, вы хотели использовать круглые скобки вместо завитушек для создания своего массива; у вас есть ссылка на хэш.

Существует также проблема с этой строкой:

 my $file1=glob ("$file");
 

Вместо того, чтобы возвращать имя файла, glob возвращает undef второй раз, потому что вы используете его в скалярном контексте и:

В скалярном контексте glob перебирает такие расширения имени файла, возвращая undef, когда список исчерпан.

Вы можете использовать glob в контексте списка, который может быть принудительно заключен в круглые скобки $file :

 use strict;
use warnings;
use feature "say";

my @arr = ("file1*.gz", "file2*.gz");
foreach my $file (@arr) {
    my ($file1) = glob($file);
    say $file1;
    if ( -e $file1 ) {
        say "File Generated using script";
    }
}
 

Этот код захватывает только первое имя файла, которое соответствует вашему шаблону. Если вы хотите, чтобы все файлы совпадали, вам нужно добавить еще for один цикл.

Ответ №2:

Вы не используете всю мощь glob функции. Как говорит toolic, вы также неправильно используете фигурные скобки {} — они создают ссылку на хэш, а не список.

Ваши параметры при обычном назначении массива обычно:

 my @arr = ('foo', 'bar');    # parenthesis
my @arr = qw(foo bar);       # "quote word", basically a string split on space
 

Но это не имеет отношения к ответу на ваш вопрос: как найти имена существующих файлов, которые соответствуют глобальному выражению.

Во-первых, аргумент to glob может содержать несколько шаблонов, разделенных пробелом. Например, из документации perldoc -f glob:

glob("*.c *.h") соответствует всем файлам с .c .h расширением или.

Вы должны прочитать всю документацию, она очень поучительна и обладает основными знаниями Perl.

Таким образом, вам не нужно перебирать количество шаблонов глобусов, просто объедините их. Например.

 my $globs = "file1*.gz file2*.gz";   # two patterns at once
 

Но это еще не все. Вы можете использовать фигурные скобки в глобусах, создавая чередование. Например, {1,2} создаст два чередования с 1 и 2 соответственно, чтобы мы могли еще больше упростить ваше выражение

 my $globs = "file{1,2}*.gz";         # still two patterns at once
 

И это еще не все. Вам не нужно хранить эти шаблоны глобусов в массиве и перебирать его, вы можете просто перебирать сам результат глобуса. Например.

 for my $file (glob $globs) {         # loop over globs
 

Вам также не нужно проверять, существует ли файл с -e помощью, поскольку глобус уже позаботится об этой проверке. Если глобус не возвращает имя файла, он не был найден. Это работает почти так же, как использование глобусов в командной строке в bash.

Короче говоря, вы можете использовать что-то вроде этого:

 use strict;
use warnings;
use feature "say";

foreach my $file (glob "file{1,2}*.gz") {
    say "File '$file1' found";
}
 

Ответ №3:

Возможно, OP предполагал что-то вроде

 use strict;
use warnings;
use feature 'say';

my @patterns = qw/file1*.gz file2*.gz/;

for my $pat (@patterns) {
    say 'Pattern: ' . $pat;
    for my $fname ( glob($pat) ) {
        say "t$fname :: File Generated using script" if -e $fname;
    }
}
 

Комментарии:

1. Глобус покажет, существует ли имя файла. Ваше if утверждение избыточно. Кроме того, ваш код дублирует то, что уже пытался сделать OP.

2. @TLP — if оператор взят из кода OP (возможно, OP следует исследовать использование glob )