I am trying to zip files from a directory. It works well except when the file name has spaces.
Since glob
splits its parameter on spaces, I also tried bsd_glob
but it did not work.
How do I handle spaces in the file names? I am seeking to retrieve all files.
#Directory of focus
my $log = 'C:/Users/me/Desktop/log';
my @files = bsd_glob( $log.'/*.*' );
#Copy contents to new directory to be zipped
foreach my $file (@files) {
copy($file, $logout) or die
"Failed to copy $file: $!\n";
}
Fail to copy
# Create Child tmp
my $out = 'C:/Users/me/Desktop/out';
mkdir $out;
# Directory of focus
my $log = 'C:/Users/me/Desktop/log';
opendir (DIR, $log) or die $!;
while ( my $file = readdir(DIR) ) {
next if $file =~ /^\./;
#print "$file\n";
copy($file, $out) or die "Failed to copy $file: $!\n";
}
closedir (DIR);
There isn't any conflict in your code, as spaces won't matter in the files that glob finds, only in the pattern that you pass to it as a parameter. I notice that you write in a comment on Matt Jacob's post
I'm sorry, the process works. Thank you! Apparently the file is opened elsewhere
so I imagine that that was the problem all along. But I thought it would be useful if I explained how to get glob
to cope with a pattern that contains spaces
glob
with spacesI would write
my @files = glob "$log/*.*"
because I think it is clearer, but the string you're passing to glob
is C:/Users/me/Desktop/log/*.*
which has no spaces, so glob
is fine
If you had a space in the path somewhere then you're right - glob
would split at those spaces and treat each part as a separate parameter. Say you had
my @files = glob "C:/Program Files/*"
then you would get the list ('C:/Program')
because glob
checks whether a file exists only if there is a wildcard in the pattern. So we get back the first part C:/Program
which doesn't have a wildcard, but the second part contributes nothing more because there are no files matching Files/*
The solution in this case is to wrap patterns that contain spaces in a pair of quotation marks - either single or double. So either of
my @files = glob "'C:/Program Files/*'"
or
my @files = glob '"C:/Program Files/*"'
will work fine. But if you want to interpolate a path like your C:/Users/me/Desktop/out
then the outermost quotes must be double quotes. In your case that would look like
my $log = 'C:/Users/me/Desktop/log';
my @files = glob "'$log/*.*'";
but I prefer to use the alternative qq
operator like this
my $log = 'C:/Users/me/Desktop/log';
my @files = glob qq{"$log/*.*"};
The alternative, as you point out in your question, is to add
use File::Glob 'bsd_glob'
to the top of your code and use the bsd_glob
function instead, which treats spaces in the pattern the same as any other character and doesn't split on them.
Or if you have
use File::Glob ':bsd_glob'
(note the additional colon) then the standard glob
call will behave the same way as bsd_glob
, which allows you to use the angle bracket form of glob
like this
my @files = <C:/Program Files/*>
without any problems