【问题标题】:Why is there a difference between using a list or a string with subprocess.Popen and quotes on the commandline为什么在命令行上使用带有 subprocess.Popen 和引号的列表或字符串有区别
【发布时间】:2015-02-02 05:18:11
【问题描述】:

运行以下脚本时:

import os
import sys
import subprocess

if len(sys.argv) > 1:
    print sys.argv[1]
    sys.exit(0)

commandline = [sys.executable]
commandline.append(os.path.realpath(__file__))
commandline.append('"test"')

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

p = subprocess.Popen(" ".join(commandline))
p.wait()

它返回以下输出

"test"
test

为什么提供参数列表或一个字符串之间存在差异? 这是在 Windows 机器上运行的,您会在任务管理器中的命令上的引号前看到反斜杠。

我希望两次运行的结果相同。

编辑:

问题不在于自动转义空格(我发现这是程序员的责任),而是更多关于我的引号是否在进程命令行中被转义。

这是从 windows 任务管理器中提取的两个子进程:

一个不同的非 python 进程使用反斜杠解析第一个命令行,这会带来意想不到的行为。我怎样才能拥有它,以便我可以使用列表而不是在命令行上转义引号?

编辑2:

引号肯定是由python添加的。如果您运行以下命令:

import subprocess

commandline = ['echo']
commandline.append('"test"')
commandline.append('>')
commandline.append(r'D:\test1.txt')

p = subprocess.Popen(commandline, shell=True)
p.wait()

commandline = 'echo "test" > D:\\test2.txt'
p = subprocess.Popen(commandline, shell=True)
p.wait()

然后你会看到输出是

D:\test1.txt:

\"test\" 

D:\test2.txt:

"test" 

【问题讨论】:

    标签: python python-2.7 subprocess quotes popen


    【解决方案1】:

    字符串 API 很危险,因为它可能会改变参数的含义。示例:您要执行C:\Program Files\App\app.exe。如果使用Popen()的字符串版本,会报错:

    C:\Program: Error 13
    

    使用字符串 API 会发生什么情况,Python 将用空格分割输入,并尝试使用单个参数 Files\App\app.exe 启动命令 C:\Program。要解决此问题,您需要正确引用。当你的论点中有引号时(即当你真的想将 "test" 作为参数传递 引号时),这会让你陷入引用地狱。

    为了解决这个(和其他微妙的)错误,有一个列表 API,其中列表的每个元素将成为一个单独的项目,无需任何修改即可传递给操作系统。使用列表 API,您可以得到所见即所得。如果您使用列表 API 引用参数,它将与引号一起传递。如果有空格,他们不会分裂你的论点。如果有任意的其他特殊字符(如*%),它们都会被传递。

    [编辑] 像往常一样,Windows 上的事情要复杂得多。 From the Python documentation for the subprocess module:

    17.1.5.1。在 Windows 上将参数序列转换为字符串

    在 Windows 上,args 序列被转换为可以使用以下规则(对应于 MS C 运行时使用的规则)解析的字符串:

    1. 参数由空格分隔,空格可以是空格,也可以是制表符。
    2. 用双引号括起来的字符串被解释为单个参数,无论其中包含什么空格。带引号的字符串可以嵌入到参数中。
    3. 前面有反斜杠的双引号被解释为文字双引号。
    4. 反斜杠按字面意思解释,除非它们紧跟在双引号之前。
    5. 如果反斜杠紧跟在双引号之前,则每对反斜杠都被解释为文字反斜杠。如果反斜杠的数量是奇数,则最后一个反斜杠会按照规则 3 中的说明转义下一个双引号。

    所以反斜杠在那里是因为 MS C 运行时希望这样。

    【讨论】:

    • 您好,谢谢您的回答。我编辑了我的问题以更清楚地说明实际问题。
    • 如果没有引号,在将元素添加到列表时必须省略它们。
    • 但我确实想要引号。当子进程启动时,我只是不希望它们在它们之前带有斜线。看我提供的图片。第二行使用 1 个字符串作为 Popen 的输入,并且正确设置了引号。第一行是使用列表作为 Popen 的输入,并且前面有反斜杠,这是错误的。根据你的逻辑,我相信其他论点也应该得到引用,而他们没有。
    • Python 没有反斜杠。它将列表传递给您的操作系统。我的第一个猜测是任务管理器添加了这些。更重要的是:你为什么还要引号?也许有更好的方法来实现你想要的。
    • 对不起,你错了。我再次编辑了我的问题并添加了一个新的代码示例。我需要引号的原因是因为外部程序会解析这样的参数:app.exe -something -value="bla123" 其中引号是强制性的。
    猜你喜欢
    • 2021-09-18
    • 2011-03-27
    相关资源
    最近更新 更多