aknuds1
aknuds1

Reputation: 68097

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?

Upvotes: 3

Views: 492

Answers (2)

Piotr Dobrogost
Piotr Dobrogost

Reputation: 42465

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 "

Upvotes: 1

Dennis Williamson
Dennis Williamson

Reputation: 360495

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

References:

Upvotes: 0

Related Questions