Причудливое поведение perl с glob

use strict;
use warnings;
#only linux
#use diagnostics;

# - - - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - -
sub in_function {
    my $file = shift;

    glob($file) or die ("$file file was not found\n"); #this fails second time called

    # this is ok second time called
    #my @dummy = glob($file) or die ("$file file was not found\n");
}
# - - - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - -
my $file = "/tmp/file1*.pdf";
glob($file) or die ("$file file was not found\n");
in_function($file);
$file = "/tmp/file2*.pdf";
glob($file) or die ("$file file was not found\n");
in_function($file);

Первый глобус в порядке Первый глобус в_функции в порядке Второй глобус в порядке Второй глобус в_функции терпит неудачу Зачем мне нужно присваивать глобус переменной при вызове внутри функции?


person Paul    schedule 19.09.2014    source источник
comment
Какая польза была бы от glob, если бы вы не использовали возвращаемое значение? glob or die вряд ли будет полезным способом использования glob.   -  person TLP    schedule 19.09.2014
comment
Казалось, самый простой способ проверить наличие имени файла с подстановочным знаком. Открыт для предложений.   -  person Paul    schedule 19.09.2014
comment
В каком-то смысле это похоже на XY-проблему. Как решение, которое зашло слишком далеко в неправильном направлении, и вам нужно сделать несколько шагов назад, чтобы найти хорошее решение. Во-первых, если бы это был я, я бы предпочел проверить точные имена файлов с помощью цикла, если это возможно. И является ли проверка существования имени файла лучшим способом убедиться, что все, что вы хотели проверить, произошло? glob может дать ложное срабатывание на существование файла. Попробуйте, например, удалить * из строки, и вы увидите, что всегда получаете совпадение.   -  person TLP    schedule 19.09.2014
comment
@Paul: но он не проверяет наличие имени файла с подстановочным знаком. попробуйте glob('{a,b}') например   -  person ysth    schedule 19.09.2014
comment
file_a_v1.txt file_b.txt file_c_v3.txt Необходимо знать, что файлы a, b, c существуют. файл_а*.txt файл_b*.txt файл_c*.txt версий не знаю, просто на фс должны быть а,б,с.   -  person Paul    schedule 19.09.2014
comment
Я понимаю. Возможно, нужно сначала получить все файлы, снять расширение версии, а затем сравнить списки. Список файлов в fs vs список файлов, которые должны существовать...   -  person Paul    schedule 19.09.2014
comment
@ysth: это вводит в заблуждение. glob вернет только имена существующих файлов, если только не содержит без подстановочных знаков * или ? или класса символов [abc]. Хотя это означает, что простое имя файла без метасимволов будет просто отображено (например, glob 'abc' вернет abc независимо от того, существует ли оно), вы можете принудительно проверить каталог, поместив один из символов в класс символов, например glob '[a]bc'   -  person Borodin    schedule 19.09.2014
comment
@Paul: Если ваши имена файлов реалистичны, я бы предложил glob 'file_[abc]*.txt', но вам придется проверить полученный список отдельно, чтобы убедиться, что присутствуют все варианты a, b и c.   -  person Borodin    schedule 19.09.2014
comment
@Borodin: не вводит в заблуждение; Я предполагаю, что шаблон здесь исходит от пользовательского ввода (или зачем его проверять?), поэтому он должен быть надежным. я бы сделал () = grep -f, glob $pattern or die   -  person ysth    schedule 19.09.2014
comment
@ysth: в этом контексте это нормально, но [glob] не проверяет наличие имени файла с подстановочным знаком просто неверно.   -  person Borodin    schedule 19.09.2014
comment
@ysth: На самом деле обратное ближе к действительности: glob проверит наличие файлов только, если передаваемый вами шаблон содержит подстановочные знаки, то есть *, ? и класс символов [...]   -  person Borodin    schedule 20.09.2014


Ответы (1)


Из perldoc -f glob

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

Следующее поможет:

() = glob($file) 
   or die ...;

Но вы, вероятно, хотите знать, что такое совпадения, поэтому вы можете использовать

my @matches = glob($file) 
   or die ...;
person mpapec    schedule 19.09.2014
comment
При вызове как таковом: glob() или die, какой это контекст внутри функции? При вызове как таковом: glob() или die, что это за контекст, если не внутри функции? - person Paul; 19.09.2014
comment
@Paul, в обоих случаях это скалярный контекст. Обратите внимание, что первый вызов glob в скалярном контексте запускает итератор. - person mpapec; 19.09.2014
comment
Что-то упустил или не объяснил. glob() или die отлично работают, когда НЕ находятся в вызове функции. Его можно вызывать неоднократно, и он работает так, как ожидалось. Таким образом, два файла выше существуют. Трижды вызывается glob (main, function, main = success), четвертый раз при сбое функции. Поведение внутри функции отличается от поведения вне функции. - person Paul; 19.09.2014
comment
P.S. () = glob($file) изменяет его на контекст списка? - person Paul; 19.09.2014
comment
Все, что я хочу знать, это существует ли какой-либо файл, соответствующий подстановочному знаку, если не умрет. - person Paul; 19.09.2014
comment
@Paul my @matches = glob($file) or die .. было бы идиоматично в Perl, и вам не нужно смотреть на @matches, если вы этого не хотите. - person mpapec; 19.09.2014
comment
@Paul: никакой разницы в функции или нет, но каждый оператор glob в источнике является отдельным итератором, поэтому вы не увидите проблему, если не вернетесь каким-либо образом. - person ysth; 19.09.2014
comment
Но это не скалярный контекст, glob вызывается в пустом контексте. Изменить: я вижу, что моя ошибка &x or die является скалярным контекстом из-за or... я думаю. - person amphetamachine; 19.09.2014
comment
@ytsh: глоб в функции и ее итератор используются повторно (не были назначены)? Это то, что я искал. Все еще неуверенно, но имеет смысл. Любые ссылки или информация о том, почему... теперь более общий вопрос о perl. - person Paul; 19.09.2014
comment
@amphetamachine eval.in/195759 - person mpapec; 19.09.2014
comment
@Paul, да, () = glob($file) вызывает glob в контексте списка и, если все выражение находится в скалярном контексте, таком как or, возвращает количество элементов, возвращаемых glob. - person ysth; 19.09.2014
comment
@amphetamachine: Пустой контекст обычно рассматривается как частный случай скалярного контекста. Очень немногие функции меняют свое поведение, кроме контекста list и scalar/void. - person Borodin; 19.09.2014