问题
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;}
}
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.
回答1:
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>";
}
Output:
1
2
3
<undef>
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.
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;
}
来源:https://stackoverflow.com/questions/18600586/perl-glob-strange-behaviour