Eryk Sun <eryk...@gmail.com> added the comment:

This PR works around a bug in CMD, so I'm inclined to close it as a third-party 
issue. 

CMD is supposed to implement the following behavior:

    1.  If all of the following conditions are met, then quote 
        characters 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
          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, preserving
        any text after the last quote character.

In particular quotes should only be preserved if the quoted string is "the name 
of an executable file". To determine this, CMD calls an internal function named 
SearchForExecutable. This function special cases any command that begins with 
"cmd " (case insensitive) by substituting the current value of the %ComSpec% 
environment variable for the *entire* string. Of course this search succeeds, 
so it ends up handling the string "cmd /c echo hello" as if it's an executable. 
Probably no has noticed this bug since running `cmd /c "cmd /c ..."` is kind of 
a weird thing to do.

To demonstrate this bug, let's compare running "cmd /c ..." with "cmd.exe /c 
...":

    >>> subprocess.check_output('cmd /c "cmd /c echo hello"')
    b'hello"\r\n'


    >>> subprocess.check_output('cmd /c "cmd.exe /c echo hello"')
    b'hello\r\n'

Adding /S makes CMD always use the old behavior that strips the quotes. 
However, this will change the existing behavior when the command line is an 
unquoted executable path with spaces in it. For example:

    >>> sys.executable
    'C:\\Program Files\\Python36\\python.exe'

    >>> subprocess.call(sys.executable, shell=True)
    Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:54:40) [MSC v.1900 64 bit 
(AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> exit()
    0

With /S, CMD strips the quotes from the command. Without the quotes it parses 
"C:\Program" as the executable to run:

    >>> subprocess.call('cmd /s /c "{}"'.format(sys.executable))
    'C:\Program' is not recognized as an internal or external command,
    operable program or batch file.
    1

----------
nosy: +eryksun
versions:  -Python 3.4, Python 3.5

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue34064>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to