Perl Glob奇怪的行为 [英] Perl glob strange behaviour
问题描述
我有一段perl代码:
I have a piece of perl code:
if (glob("$data_dir/*$archivefrom*")) {
my $command1 = "zip -r -T -m $backup_dir/$archivefrom.zip $data_dir/*$archivefrom*";
my $err_cmd1 =system("$command1");
if ($err_cmd1 != 0){print "Error $command1\n";exit 1;}
}
有时if返回true,但是zip匹配任何内容,为什么会发生这种情况?同时,没有并发进程会删除文件,只是glob返回的文件与zip归档文件匹配项有所不同,即使它为空,它也会返回非空结果.
sometimes the if returns true but the zip would not match anything, why would that happen? There is no concurrent processes that would remove files in the meantime, it's just glob is returning something different from zip archive match for files, it returns non-empty result even though it should be empty.
推荐答案
标量上下文中的glob
函数将成为迭代器,而不是文件是否存在的测试!可以通过以下代码证明这一点:
The glob
function in scalar context becomes an iterator, not a test for file existence! This can be demonstrated by the following code:
use feature 'say';
my @patterns = ('{1,2,3}', 'a', 'b', 'c');
for my $pattern (@patterns) {
my $item = glob $pattern;
say $item // "<undef>";
}
输出:
1
2
3
<undef>
也就是说,glob
会记住给定的 first 模式,然后对所有匹配项进行迭代,但是在迭代器耗尽之前,不要使用它给出的任何新模式.因此,在表达式glob("$data_dir/*$archivefrom*")
中,无法识别$data_dir
和$archivefrom
变量中的更新值.在所有可能的结尾,您还将获得一个undef
返回值.那么if
分支显然没有执行.
That is, glob
remembers the first pattern it was given, then iterates over all matches, but not use any new patterns it was given until the iterator is exhausted. Therefore in your expression glob("$data_dir/*$archivefrom*")
, updated values in the $data_dir
and $archivefrom
variables are not recognized. You will also get one undef
return value at the end of all possibilities. Then the if
branch obviously isn't executed.
要测试是否存在至少一个与模式匹配的文件,您必须立即获取所有匹配项,从而避免了迭代.为此使用列表上下文.我们可以使用伪运算符()=
来计算匹配数-≥1的任何值都可以.我们还可以将 first 匹配项分配给一个变量,并在您的system
命令中使用它,以避免出现壳插值问题:
To test if at least one file matching your pattern exists, you have to fetch all matches at once, thus avoiding the iteration. Use list context for that. We could use the pseudoperator ()=
to count the number of matches – anything ≥ 1 is fine. We can also assign the first match to a variable, and use it in your system
command, to avoid shell interpolation issues:
use autodie ':system'; # automatic error handling, additionally requires IPC::System::Simple
if (my ($archivePath) = glob "$data_dir/*$archiveFrom*") {
system 'zip', '-r', '-T', '-m', "$backup_dir/$archivefrom.zip", $archivePath;
}
这篇关于Perl Glob奇怪的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!