开发者

On Windows, how can I protect arguments to shell scripts using Python 2.7 subprocess?

Consider for example the following Python code:

subprocess.call([r'.\tst.bat', '"1|2"'])

Here I've put double quotes around the argument to tst.bat, in order to protect '|' from the shell since tst.bat will ultimately be run via the Windows shell. However, if there are double quotes in arguments, subprocess in开发者_开发技巧 Python 2.7 escapes them. The result is that tst.bat receives this argument: \"1|2\".

How can I escape the argument "1|2" so that it's passed untransformed to tst.bat?


Subprocess module on Windows in case of a list of arguments given to the call method transforms this list into a string using list2cmdline function. In the docstring of this function one can read:

3) A double quotation mark preceded by a backslash is interpreted as a literal double quotation mark.

According to this the solution of your problem should look like this

subprocess.call([r'.\tst.bat', r'\"1|2\"'])

However it seems like there's a mismatch between documentation and implementation of list2cmdline function;

Python 2.7.4 (default, Apr  6 2013, 19:55:15) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess
>>> print subprocess.list2cmdline([r'\"1|2\"'])
\\\"1|2\\\"

The same behavior is in Python 3.3.1. I raised a bug at http://bugs.python.org/issue18649

UPDATE

It turns out I was confused by very misleading docstring of list2cmdline function - see http://bugs.python.org/issue18649 for details.

The sequence of arguments passed to subprocess.call is translated by list2cmdline function which is concerned only with the quoting mechanism used by MS C runtime and not by quoting mechanism used by cmd.exe. This makes passing arguments - which are later to be interpreted by cmd.exe - to subprocess.call as a list either very awkward or impossible.

There's one more chance to get it working in this case, though. list2cmdline double quotes every argument with a space or tab inside. If having a space at the end of your argument does not break the batch file you can add it at the end forcing double quoting as you wanted.

>>> import subprocess
>>> print subprocess.list2cmdline(['1|2 '])
"1|2 "


This (or a similar problem) has been reported as a bug.

References:

  • http://bugs.python.org/issue2304
  • http://bugs.python.org/issue11139
  • http://bugs.python.org/issue8972
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜