Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I open a file when I use glob on a directory with a space in the name?

Tags:

perl

I recently started working with Perl as a requirement for an education class. Part of our homework is to open a text file, read some lines, and then close the file.

I created a folder on the desktop and put the required text files in it. I wrote the following code to open each file, read a line, and close it:

my $dir = 'C:\Users\Jay Zabaluski\Desktop\Shakespeare';

opendir (DIR, $dir) or die "cannot opendir $dir";

foreach my $fp (glob("$dir/*.txt")) {

  printf "%s\n", $fp;

  open my $fh, "<", $fp or die "can't read open '$fp': $OS_ERROR";
  my $firstLine = <$fh>;
  print "$firstLine\n";

  close $fh or die "can't read close '$fp': $OS_ERROR";
}

When I run this script on Padre, the Perl IDE, I get this error:

C:./UsersJay
can't read open 'C:./UsersJay': at example.pl line 5
Press any key to continue.....

I don't understand why I'm getting this error unless I'm somehow mistakenly using \ instead of /, but when I right-click on a file in Windows Explorer, the path always shows up with backslashes, e.g. C:\something\something.

I tried changing the file path to use forward slashes as suggested by OnlineCop in the comments, but got a similar error:

C:/Users/Jay
can't read open 'C:/Users/Jay': at example.pl line 5
Press any key to continue.....
like image 453
user2128074 Avatar asked Dec 03 '25 17:12

user2128074


2 Answers

As others have observed, the problem is that your call to glob

glob("$dir/*.txt")

uses this definition of $dir

my $dir = 'C:\Users\Jay Zabaluski\Desktop\Shakespeare';

so the call is equivalent to this

glob('C:\Users\Jay Zabaluski\Desktop\Shakespeare/*.txt')

So the parameter has two components, C:\Users\Jay and Zabaluski\Desktop\Shakespeare/*.txt, which isn't at all what you meant.

The solution is to enclose the entire wildcard pattern in double quotes, so you could use the qq operator to define a new delimiter, different from ", that will interpolate embedded variables.

For example, try

my $glob_pattern = qq{"$dir/*.txt"};
say $glob_pattern;

and you will see that the parameter actually passed to glob is

"C:\Users\Jay Zabaluski\Desktop\Shakespeare/*.txt"

including the double quotes, which are essential.

like image 177
Borodin Avatar answered Dec 06 '25 08:12

Borodin


foreach my $fp (glob qq("$dir/*.txt")) {

perldoc -f glob :

Note that "glob" splits its arguments on whitespace and treats
each segment as separate pattern. As such, "glob("*.c *.h")"
matches all files with a .c or .h extension. The expression
"glob(".* *")" matches all files in the current working directory.
If you want to glob filenames that might contain whitespace,
you'll have to use extra quotes around the spacey filename to
protect it. For example, to glob filenames that have an "e"
followed by a space followed by an "f", use either of:
            @spacies = <"*e f*">;
            @spacies = glob '"*e f*"';
            @spacies = glob q("*e f*");
 If you had to get a variable through, you could do this:
            @spacies = glob "'*${var}e f*'";
            @spacies = glob qq("*${var}e f*")
like image 32
AnFi Avatar answered Dec 06 '25 07:12

AnFi