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

I have read about "quotes and quote-like operators" in the perlop documentation. I think the problem here is not perl but Microsoft (Update: this is confirmed, see note and solution at bottom).

Double quotes gobbled

When run from perl
print STDERR `"echo hello"`;
produces
hello
But, when run at a DOS prompt, the command:
C:\>"echo hello"
produces
'"echo hello"' is not recognized as an internal or external command, o +perable program or batch file.
It appears that in this case, perl did not send the quotes to DOS.

Double quotes not gobbled

On the other hand, I want to execute a file which has a space in its name. For example I write a file called My Echo.pl which contains simply print "echo\n";

I create a copy of the same file with the name My Echo (v1).pl.

Now I run the following perl program:

print STDERR `"My Echo.pl"`; print STDERR `"My Echo (v1).pl"`;
And the result is
echo 'My' is not recognized as an internal or external command, operable pr +ogram or batch file.

Summary and Question

It appears that when the file name contains a parenthesis, some different kind of interpretation occurs, and the internal double quotes are lost. How can I run "My Echo (v1).pl" (without going to Linux)?

Update: I know that print STDERR `My\\ Echo (v1).pl`; will work, but for my own reasons, I want to use quotes (I don't want to parse the string an find all spaces etc).

Update: The explanation is almost surely given in the answer by Sandy. It is clear that this has nothing to do with perl and is just another weirdness of MSDOS (JAWMS). The cmd.exe drops the quotes under some circumstances. Actually the case in point doesn't match any of the documented circumstances mentioned in the documentation of cmd.exe, but then that is Microsoft. The final proof (as shown by goibhniu is the following DOS output (no perl involved):

C:\>cmd/c "My Echo.pl" echo C:\>cmd/c "My Echo (v1).pl" 'My' is not recognized as an internal or external command, operable program or batch file.

Updated Solution: Just put a space after the last quote, and DOS then does not strip the quotes in its bizzare inconsistent way. Eg: `"dos command with spaces and (parens).pl" ` I wonder if this bug is mentioned at Microsoft.

Replies are listed 'Best First'.
Re: Quotable Quotes
by cdarke (Prior) on Sep 07, 2007 at 11:53 UTC
    This is the way of Windows.
    Outside perl, Windows is doing two levels of (what we would call) interpolation. The first level is when the command is submitted from C. The 'command' in this case is the one which runs cmd.exe. That is where the quotes are stripped - and the Windows API does that.
    You are correct that by the time it arrives at cmd.exe the quotes are gone, but are forgetting the extra command-line step. Google "msdn CreateProcess" (2nd argument - lpCommandLine).
Re: Quotable Quotes
by goibhniu (Hermit) on Sep 07, 2007 at 12:34 UTC

    In your second example,

    But, when run at a DOS prompt, the command: C:\>"echo hello" produces '"echo hello"' is not recognized as an internal or external command, operable program or batch file.
    Why is there an expectation that Perl is involved at all? It looks like you threw a string in double quotes at cmd.exe.

    If you simply: C:\>echo hello you get: hello because echo is a DOS internal command.

    Perhaps your original example didn't need the double quotes?

    C:\>perl -e "print STDERR `echo hello`"; produces hello

    and I've found that when I wanted double-quotes in my on-liners on Windows, I needed (ready for absurdity?) triple double-quotes.

    C:\>perl -e "print STDERR `echo """hello"""`"; produces "hello"


    I humbly seek wisdom.
      It appears to me that everyone is missing the point. Perhaps I was too verbose in my question, so let me be terse this time.

      Ignore all the echo example, that was just to illustrate a point. My real question is just this one:

      print STDERR `"My Echo.pl"`; print STDERR `"My Echo (v1).pl"`;
      The first line works. The second doesn't. Why?

      The behavior is consistent. Any file name with a parenthesis does not work. Others seem to work just fine.

      Yes I know, I can rewrite things (eg. `perl "My Echo (v1).pl"`). My question still is: Why?

        I think I've reproduced your problem in my environment. Triple double-quotes doesn't solve it:

        C:\chas_sandbox>copy con "My Echo.pl" print "hello, world\n"; ^Z 1 file(s) copied. C:\chas_sandbox>copy con "My Echo (v1).pl" print "hello, world\n"; ^Z 1 file(s) copied. C:\chas_sandbox>"My Echo (v1).pl" hello, world C:\chas_sandbox>"My Echo.pl" hello, world C:\chas_sandbox>perl -e "print STDERR `"My Echo.pl"`;" Can't find string terminator "`" anywhere before EOF at -e line 1. C:\chas_sandbox>perl -e "print STDERR `"""My Echo.pl"""`;" hello, world C:\chas_sandbox>perl -e "print STDERR `"My Echo (v1).pl"`;" Can't find string terminator "`" anywhere before EOF at -e line 1. C:\chas_sandbox>perl -e "print STDERR `"""My Echo (v1).pl"""`;" 'My' is not recognized as an internal or external command, operable program or batch file.

        It's obviously getting to the cmd shell, since the not recognized as an internal or external command is from cmd.

        per Sandy's message, below, it's definitely the ()'s that are messing you up. And it's cmd that doesn't like them, not Perl.

        I know you're still asking "why?" but here's another tack for a work-around:

        C:\chas_sandbox>dir /x "My Echo (v1).pl" Volume in drive C has no label. Volume Serial Number is D425-A27D Directory of C:\chas_sandbox 09/07/2007 04:22 PM 25 MYECHO~2.PL My Echo (v1).pl 1 File(s) 25 bytes 0 Dir(s) 28,821,581,824 bytes free C:\chas_sandbox>perl -e "print STDERR `MYECHO~2.PL`;" hello, world C:\chas_sandbox>

        I've used dir /x to get the short name and called the script using the shortname between the backticks.


        I humbly seek wisdom.
        Maybe the '(' symbol gives some special meaning .I'm nt sure!!!

        The world is so big for any individual to conquer

Re: Quotable Quotes
by m0ve (Scribe) on Sep 07, 2007 at 08:06 UTC
    this might be what you are looking for :
    system('Perl "My Echo (v1).pl"');
Re: Quotable Quotes
by Sandy (Curate) on Sep 07, 2007 at 20:28 UTC
    Windows is weird.

    These are the rules related to commands passed to the shell via cmd /C, which I believe how perl passes the command to the operating system.

    M:\>help cmd Starts a new instance of the Windows 2000 command interpreter CMD [/A | /U] [/Q] [/D] [/E:ON | /E:OFF] [/F:ON | /F:OFF] [/V:ON | /V: +OFF] [[/S] [/C | /K] string] /C Carries out the command specified by string and then terminate +s /K Carries out the command specified by string but remains /S Modifies the treatment of string after /C or /K (see below) /Q Turns echo off ... deleted lines... If /C or /K is specified, then the remainder of the command line after the switch is processed as a command line, where the following logic i +s used to process quote (") characters: 1. If all of the following conditions are met, then quote charact +ers on the command line are preserved: - no /S switch - exactly two quote characters - no special characters between the two quote characters, where special is one of: &<>()@^| - there are one or more whitespace characters between the the two quote characters - the string between the two quote characters is the name of an executable file. 2. Otherwise, old behavior is to see if the first character is a quote character and if so, strip the leading character and remove the last quote character on the command line, preservin +g any text after the last quote character.
    I'm not quite sure why your original code worked
    print STDERR "my echo.pl"
    because it does not work for me. Possibly different flavours of Windows.

    Anyways, my echo.pl is not an executable file, it is just that the file extension is associated with an executable.

    try.pl

    eval {print `my echo.pl`}; eval {print `"my echo.pl"`;}; eval {print `perl "my echo.pl"`}; eval {print `perl "my echo (v1).pl"`};
    my echo.pl and my echo (v1).pl:
    print "hello sandy\n";
    Results "try.pl"
    M:\>try.pl Can't open perl script "M:\my": No such file or directory Can't open perl script "M:\my": No such file or directory hello sandy hello sandy
    Conclusion: Do not rely on Windows to resolve the file extionsions to determine the 'real' executable, but use the proper name (perl in this case). Quote the filename.

    Hope that helps.

Re: Quotable Quotes
by erroneousBollock (Curate) on Sep 07, 2007 at 08:10 UTC
    Your problem is not that the quotes get gobbled, it's that you're forgetting that cmd.exe runs whatever you put in backticks on windows.

    Double quotes have different meaning in cmd.exe than in most unix shells.

    -David

      I disagree. That is why I showed the first part of the question, where I wrote "echo hello" with the quotes to a DOS shell. The DOS shell would find this command illegal, yet perl does not.

      Also the second example has two identical commands. One works (without parentheses), one does not (with the (v1) in parens). If we open a DOS shell, they both work. So whatever the difference is, it is on the perl side, not in the command processor.

        Perl is not involved
        C:\>perl -e "print @ARGV" "a r g v" a r g v C:\> C:\>perl -e "print @ARGV" "\"a r g v\"" "a r g v" C:\> C:\>"echo 1" '"echo 1"' is not recognized as an internal or external command, operable program or batch file. C:\> C:\>cmd /C "echo 1" 1 C:\> C:\>cmd /C "\"echo 1\"" '\"echo 1\"' is not recognized as an internal or external command, operable program or batch file. C:\>
        my $hmm =`perl "My Echo (v1).pl"`; print $hmm;

        works btw ;)