使用Python将包含双引号的参数传递给子进程

8
我正在寻找一种方法,可以将包含双引号的参数传递给Python的subprocess模块,而不需要对双引号进行转义。我看到过类似的问题被问了几次,当引号围绕着参数时,答案通常是删除引号。但我遇到的问题是,引号是参数的一部分,必须将其传递给脚本,而不能在每个引号前面添加反斜杠。例如:我正在调用subprocesTest.bat,一个简单的批处理脚本,它接受一个参数并将其回显:
echo "%~1"

我用一个包含引号的参数从Python调用批处理脚本:

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

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

期望输出:

"Bill 说:\"嗨!\""

实际输出:

"Bill 说:\"Hi!\""

当我从命令行调用相同的批处理脚本时,可以得到期望的输出:

subprocesTest.bat "Bill 说:\"嗨!\""

查看源代码,subprocess.py中的list2cmdline函数已有文档说明:

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

然而,如果我逐步执行此函数,我发现没有办法通过不在双引号前加反斜杠的方式传递双引号:

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

所以我有两个问题...

  • 如果不添加反斜杠,是否可以向subprocess传递包含双引号的参数?
  • 如果不可能,有人能解释一下为什么设计函数是这样的吗?函数文档字符串中的第三项似乎表明我可以通过添加反斜杠来传递一个文字引用,但这并没有产生我想要的行为。我读错文档了吗?

以下是其他讨论此问题的线程,并通过不使用引号进行绕过:

我没有看到对我实际想要传递引号的情况的回应。


我在Windows上找到的唯一解决方案是使用shell=True而不是拆分参数,Popen('subprocesTest.bat "Bill said "Hi!"', shell=True);shell=False也可以(诀窍是不要拆分参数)。Cygwin的Python在使用shell=True时无法按预期工作,并且在使用shell=False时,您将在任何双引号之前获得反斜杠,并且在包含空格的参数周围有双引号。并非所有情况都有一个解决方案 :/ - Badr Elmers
1个回答

1

1)是的,但可能不能在Windows上或使用.bat文件。例如,当您运行Windows版本的此命令时会发生什么:


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)嗯,以下内容有些含糊不清:

"Bill said "Hi!""

那是引用的字符串吗:

"Bill said " 

跟着未加引号的字符串:

Hi!

跟着一个引用的空字符串:
""

?


你的myprog.py示例可以工作,只是因为subprocess在python读取参数时会在前面添加反斜杠,我猜这些反斜杠用于转义双引号。如果我从Windows命令行调用相同的myprog.py脚本并将"Bill said "Hi!""作为参数传递,那么Hi!周围的引号会消失。我想这就是为什么反斜杠总是会被添加到双引号前面的原因。 - BetterOffEd
这是一个很好的观点。我不确定Windows命令行如何解释参数,我只知道当通过子进程传递时,它的解释方式不同。也许更好的例子是一个将测量作为参数的简单脚本。我想使用子进程传递16英寸的参数,但是子进程将我的参数转换为16 \”,这不是我的距离批处理脚本所期望的。 - BetterOffEd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接