Perl glob奇怪的行为

时间:2013-09-03 20:05:03

标签: perl glob

我有一段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存档匹配不同,即使它应该为空,它也会返回非空结果。

1 个答案:

答案 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;
}