我有一段perl代码:
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存档匹配不同,即使它应该为空,它也会返回非空结果。
答案 0 :(得分:6)
标量上下文中的glob
函数成为迭代器,而不是文件存在的测试!这可以通过以下代码证明:
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
会记住它给出的第一个模式,然后迭代所有匹配,但是在迭代器耗尽之前不会使用它给出的任何新模式。因此,在您的表达式glob("$data_dir/*$archivefrom*")
中,无法识别$data_dir
和$archivefrom
变量中的更新值。在所有可能性结束时,您还将获得一个undef
返回值。那么if
分支显然不会被执行。
要测试是否存在至少一个与您的模式匹配的文件,您必须一次获取所有匹配项,从而避免迭代。使用列表上下文。我们可以使用伪操作符()=
来计算匹配数 - 任何≥1的都可以。我们还可以将第一个匹配分配给变量,并在system
命令中使用它,以避免shell插值问题:
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;
}