8

I'm looking for a way to pass an argument which contains double quotes to python's subprocess module, without the double quotes being escaped.

I've seen this question asked a few different times when the quotes are surrounding the arg, but the answer is usually to remove the quotes. The issue I've hit is that the quotes are part of the argument and must be passed to the script without prepending a back slash to each quote

example:

I'm calling subprocesTest.bat, a simple batch script that takes an argument and echos it:

echo "%~1"

I invoke the batch script from python with an arg that includes quotes:

import subprocess
test_string = 'Bill said "Hi!"'
cmd = ["subprocesTest.bat",
       test_string
       ]

p = subprocess.Popen(cmd)
p.wait()

expected output:

"Bill said "Hi!""

actual output:

"Bill said \"Hi!\""

I can get the expected output when calling the same batch script from the command line as follows:

subprocesTest.bat "Bill said "Hi!""

Looking at the source, subprocess.py's list2cmdline function is documented with:

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

However, if I step through this function, I see no means of passing a double quote through without prepending a backslash:

        elif c == '"':
            # Double backslashes.
            result.append('\\' * len(bs_buf)*2)
            bs_buf = []
            result.append('\\"')

So I have two questions...

  • Is it possible to pass an arg to subprocess which contains a double quote wihtout prepending a backslash
  • If it is not possible, can someone explain to me why the function was designed this way? Item three in the funcion's doc string seems to indicate that I can pass a literal quote by prepending a backslash, but this doesn't yield the behavior I was looking for. Am I reading the doc wrong?

Here are other threads where this question is asked, and worked around by not using quotes:

I see no response for a situation where I actually want to pass quotes in my argument

Community
  • 1
  • 1
BetterOffEd
  • 81
  • 1
  • 1
  • 4
  • Possible duplicate of [Passing double quote shell commands in python to subprocess.Popen()?](https://stackoverflow.com/questions/14928860/passing-double-quote-shell-commands-in-python-to-subprocess-popen) – xenteros Oct 10 '19 at 13:19
  • the only solution I found for this problem on windows is using shell=True and not split the args , `Popen('subprocesTest.bat "Bill said "Hi!"', shell=True)` ; shell=False also works (the trick is to not split the args). python of cygwin will not work as expected with shell=True and with shell=False you will get the backslash before any double quotes, and double quotes around args containing a space. there is no one solution for all cases :/ – Badr Elmers Jan 22 '22 at 06:49

1 Answers1

1

1) Yes, but maybe not on windows and/or with a .bat file. For example, what happens when you run the windows equivalent of this:

import subprocess

test_string = 'Bill said "Hi!"'

cmd = ["./myprog.py",
       test_string
       ]

p = subprocess.Popen(cmd)
p.wait()

myprog.py:

#!/usr/bin/env python

import sys

print '"{}"'.format(sys.argv[1])

2) Well, the following seems a bit ambiguous:

"Bill said "Hi!""

Is that the quoted string:

"Bill said " 

followed by the unquoted string:

Hi!

followed by a quoted blank string:

""

?

7stud
  • 46,922
  • 14
  • 101
  • 127
  • 1) your myprog.py example works, only because subprocess prepends the backslashes which I presume are used to escape the double quotes when python reads arguments. If I call the same myprog.py script from the windows command line and pass "Bill said "Hi!"" as the arg, the quotes around Hi! disappear. I imagine this is the reason a backslash is always prepended to a double quote – BetterOffEd Jun 06 '13 at 18:21
  • 2) This is a good point. I'm not sure how windows command line is interpretting the arguement, I just know that it is not interpreted the same when passed through subprocess. Perhaps a better example would be a simple script that takes measurements as parameters. I want to pass in 16" to signify 16 inches using subprocess, but subprocess converts my argument to 16\", which is not what my distance batch script expects – BetterOffEd Jun 06 '13 at 18:27