I'm not sure why you think you need a library function to wrap something in double quotes?
You're mixing in the quotes/escapes far too early. They're only needed in certain circumstances when they are part of a longer string that will be treated as a space-separated list of substrings. The most obvious example being a command line for cmd/bash
While you're working with the string in your program you need just the plain path string without any decoration. Once you've built your path, create your command line (or whatever) with quotes around it, and it should all work
I've never been able to get the escape character for Windows cmd (which is circumflex ^
) to work reliably, so I always wrap any strings that contain space characters in double quotes. That works on Windows and any flavour of Unix, including OSX
Here's an example using the code in your question. Note that there's no need to be so careful about using catdir
and catfile
appropriately: unless you're building a root directory like C:\
they behave identically on systems where there is no syntactical distinction between files and directories () which includes all the platforms you mention in your question
use strict;
use warnings 'all';
use File::Spec::Functions qw/ catfile /;
my $testcat = catfile('C:\Program Files', 'My Program', 'test.txt');
print qq{Test cat: "$testcat"\n};
system qq{type "$testcat"};
output
Test cat: "C:\Program Files\My Program\test.txt"
TESTCAT CONTENTS
Update
Here's another example showing how path segments that have reached your program can be unquoted before they're used. I've defined three scalar variables. Some or all of those may have originated outside your program, while others may be defined like this, as string literals. The point is that $root
is enclosed in unwanted double quotes; it is an invalid path segment and won't work if you pass it to catfile
So I've written a little subroutine unquote
and applied it to all three as we're pretending we don't know which of the segments are quoted and which are not. As you can see from the output, it removes the quotes from $root
but leaves the other two strings untouched. Now they're all valid and okay to pass to catfile
The output shows that catfile
returns Test cat: C:\Program Files\My Program\test.txt
which is what we want. Now suppose we want to type it, so we need to create the command line
type "C:\Program Files\My Program\test.txt"
In the context of the command line, the double quotes are necessary to delimit the path string, but they not part of the path
Again, as you can see, the call to system
works fine. My file contains TESTCAT CONTENTS
, and that is what my program prints
I hope that helps?
use strict;
use warnings 'all';
use feature 'say';
use File::Spec::Functions qw/ catfile /;
my ($root, $dir, $file) = ( '"C:\Program Files"', 'My Program', 'test.txt');
print <<END;
Original:
Root: $root
Dir: $dir
File: $file
END
unquote($_) for $root, $dir, $file;
print <<END;
Unquoted:
Root: $root
Dir: $dir
File: $file
END
my $testcat = catfile($root, $dir, $file);
say "Full path: $testcat";
my $cmd = qq{type "$testcat"};
say "Command is:\n$cmd\n";
system $cmd;
sub unquote {
$_[0] =~ s/\A"([^"]*)"\z/$1/;
$_[0];
}
output
Original:
Root: "C:\Program Files"
Dir: My Program
File: test.txt
Unquoted:
Root: C:\Program Files
Dir: My Program
File: test.txt
Full path: C:\Program Files\My Program\test.txt
Command is:
type "C:\Program Files\My Program\test.txt"
TESTCAT CONTENTS