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