LloydRice has asked for the wisdom of the Perl Monks concerning the following question:

Is there any place I can learn more about using the dir/file tests in Windows for path names which include spaces? I have written a couple of short scripts to test some ways of doing this. First, the simple case:

$me = "dirtest1"; # Perl script to test variations on file/dir test argument quoting print "All of the following conditions are true on my system.\n"; print "The issue is to see which tests work.\n"; print "The path includes a directory name containing a space.\n"; print "\n"; print "\nThese tests use a single, defined string as path:\n"; # This example would not run due to compiler errors # $expl = "Bare unquoted text with single backslashes"; # if ( -e C:\users\public\Music\Sample Music ) # { print "'-e $expl' is true\n"; } else { print "'-e $expl' is false\ +n"; } # This example would not run due to compiler errors # $expl = "Bare unquoted text with double backslashes"; # if ( -e C:\\users\\public\\Music\\Sample Music ) # { print "'-e $expl' is true\n"; } else { print "'-e $expl' is false\ +n"; } $expl = "Single-quoted text with single backslashes"; if ( -e 'C:\users\public\Music\Sample Music' ) { print "'-e $expl' is true\n"; } else { print "'-e $expl' is false\n" +; } $expl = "Single-quoted text with double backslashes"; if ( -e 'C:\\users\\public\\Music\\Sample Music' ) { print "'-e $expl' is true\n"; } else { print "'-e $expl' is false\n" +; } $expl = "Double-quoted text with double backslashes"; if ( -e "C:\\users\\public\\Music\\Sample Music" ) { print "'-e $expl' is true\n"; } else { print "'-e $expl' is false\n" +; }
This works pretty much as I expected.
All of the following conditions are true on my system. The issue is to see which tests work. The path includes a directory name containing a space. These tests use a single, defined string as path: '-e Single-quoted text with single backslashes' is true '-e Single-quoted text with double backslashes' is true '-e Double-quoted text with double backslashes' is true
I was a little surprised that the second test worked. I deleted several other versions which failed.

Now for the real test. This one stumps me.

$me = "dirtest2"; # Perl script to test variations on file/dir test argument quoting print "All of the following conditions are true on my system.\n"; print "The issue is to see which tests work.\n"; print "The final path includes a directory name containing a space.\n" +; print "\n"; $part1 = "C:\\users\\public\\Music"; $part2 = "Sample Music"; $dfull = "$part1\\$part2"; print "\nThese tests use a path consisting of concatenated substrings: +\n"; print " part1 = '$part1'\n"; print " part2 = '$part2'\n"; print " dfull = '$dfull'\n"; print "\n"; $expl = "Part1, unquoted"; if ( -e $part1 ) { print "'-e $expl' is true\n"; } else { print "'-e $expl' is false\n" +; } $expl = "Full path, unquoted"; if ( -e $full ) { print "'-e $expl' is true\n"; } else { print "'-e $expl' is false\n" +; } $expl = "Part1 in single quotes"; if ( -e '$part1' ) { print "'-e $expl' is true\n"; } else { print "'-e $expl' is false\n" +; } $expl = "Full path in single quotes"; if ( -e '$full' ) { print "'-e $expl' is true\n"; } else { print "'-e $expl' is false\n" +; } $expl = "Part1 in double quotes"; if ( -e "$part1" ) { print "'-e $expl' is true\n"; } else { print "'-e $expl' is false\n" +; } $expl = "Full path in double quotes"; if ( -e "$full" ) { print "'-e $expl' is true\n"; } else { print "'-e $expl' is false\n" +; }
The results are disappointing.
All of the following conditions are true on my system. The issue is to see which tests work. The final path includes a directory name containing a space. These tests use a path consisting of concatenated substrings: part1 = 'C:\users\public\Music' part2 = 'Sample Music' dfull = 'C:\users\public\Music\Sample Music' '-e Part1, unquoted' is true '-e Full path, unquoted' is false '-e Part1 in single quotes' is false '-e Full path in single quotes' is false '-e Part1 in double quotes' is true '-e Full path in double quotes' is false
I have yet to find any way to get the correct results with a path string I have built from separate variables.

Replies are listed 'Best First'.
Re: Win file/dir names w/spaces
by Corion (Patriarch) on Mar 22, 2014 at 21:14 UTC

    To understand how single and double quotes work in Perl, maybe perlop helps you.

    The problem at hand is really simple, and had you used strict, Perl would have told you about your usage of $dfull and $full.

    I recommend to also print out the value you are actually checking with the -X test as follows:

    my $dir= $part1; if( -e $dir ) { print "-e $dir is true\n" } else { print "-e $dir is false\n" };

    That way, you will see what expressions you actually check, and you'll find out that $path is empty, as $dpath contains the value you've constructed.

Re: Win file/dir names w/spaces
by kcott (Archbishop) on Mar 23, 2014 at 06:19 UTC

    G'day LloydRice,

    You appear to have answers to your questions from various monks.

    Seeing the amount of code you wrote for your tests, I thought I'd introduce you to the built-in module Test::More.

    I don't have Perl running on an MSWin platform (so I can't duplicate your exact tests) but the following should give you an idea of how much coding this module can save you. I also think that, with the substantially reduced code, the tests themselves become far more obvious and the code is more readable and maintainable.

    #!/usr/bin/env perl use strict; use warnings; use Test::More tests => 3; ok(-e '/Users/ken/tmp/Sample Music', 'Single quotes'); ok(-e "/Users/ken/tmp/Sample Music", 'Double quotes'); ok(-e "'/Users/ken/tmp/Sample Music'", 'Single quotes in double quotes +');

    Output:

    1..3 ok 1 - Single quotes ok 2 - Double quotes not ok 3 - Single quotes in double quotes # Failed test 'Single quotes in double quotes' # at ./pm_example.pl line 10. # Looks like you failed 1 test of 3.

    -- Ken

      Thanks to all who weighed in on this. I have learned a lot. Judging by the tone of many of the replies, some will be glad to hear that I have started using "strict" (at least some of the time).

      However, it turns out that the real problem was that I was mixing Perl functions for file operations with Win command lines executed via qx. What I had not considered (and learned) was that qx actions go through the Win command line interpreter, but the Perl functions, in particular, the -x tests, do not. The difference is, of course, that path/file names with spaces get chopped up by the CLI and thus required enclosing Dquotes, but work fine in the -x tests, in which case, the Dquotes mess things up.

      I am now using the Perl file operations in Win32::File and Win32::CopyFile and nearly everything is working. A little more clean-up and the job will be done.

      Again, thanks for all the help.

      Lloyd.

Re: Win file/dir names w/spaces
by LloydRice (Beadle) on Mar 22, 2014 at 21:11 UTC

    I then tried the File::Spec module. It helps.

    $me = "dirtest3"; # Perl script to test variations on file/dir test argument quoting use File::Spec; print "All of the following conditions are true on my system.\n"; print "The issue is to see which tests work.\n"; print "The final path includes a directory name containing a space.\n" +; print "\n"; $part1 = "C:"; $part2 = "users"; $part3 = "public"; $part4 = "Music"; $part5 = "Sample Music"; $full = File::Spec->catfile( $part1, $part2, $part3, $part4, $part5 ); print "\nThese tests use a path consisting of concatenated substrings: +\n"; print " full = '$full'\n"; print "\n"; $expl = "Full path, unquoted"; if ( -e $full ) { print "'-e $expl' is true\n"; } else { print "'-e $expl' is false\n" +; } $expl = "Full path in single quotes"; if ( -e '$full' ) { print "'-e $expl' is true\n"; } else { print "'-e $expl' is false\n" +; } $expl = "Full path in double quotes"; if ( -e "$full" ) { print "'-e $expl' is true\n"; } else { print "'-e $expl' is false\n" +; }
    Again, I was a bit surprised at the second case. But I can use one of the other two cases.
    All of the following conditions are true on my system. The issue is to see which tests work. The final path includes a directory name containing a space. These tests use a path consisting of concatenated substrings: full = 'C:\users\public\Music\Sample Music' '-e Full path, unquoted' is true '-e Full path in single quotes' is false '-e Full path in double quotes' is true

Re: Win file/dir names w/spaces
by LloydRice (Beadle) on Mar 22, 2014 at 21:25 UTC

    OK. Finally. Here's my real question.

    What's the difference between the strings $dfull in test2 and $full in test 3? I know that $full did not print correctly in test3 because it was single quoted in the print statement. But that is really part of my question. What is different about a string that parses correctly with or without single quotes. I understand that double quotes trigger interpolation. But single quotes don't do that. What do they do?

      What's the difference between the strings $dfull in test2 and $full in test 3?

      Just to retrace your steps a bit, do you understand the difference between  $dfull in dirtest2 and  $full also in dirtest2? Had strictures (see strict) been enabled, Perl would have refused to compile  $full because it was not pre-defined. Without strictures but with warnings enabled, Perl would have told you that  $full was undefined wherever you used it in this state. These two pragmata can be enormously useful to the learning (and even the experienced) programmer. A word to the wise...

      And certainly do study and understand the difference between interpolating (double-quotish) and non-interpolating (single-quotish) string operators.

      See perlop: Quote and Quote like operators. Understanding Perl's string handling generally and the different quote types particularly is fundamental to making good use of Perl.

      If the code changes take longer than the time saved, it's fast enough already.

      Thanks, Corion. I will reread perlop and study these cases some more.