执行子进程失败

19

我尝试使用Python通过多个参数调用进程。对于我自己来说,执行批处理文件本身很好,但将其转换为Python让我感到非常困惑。以下是批处理文件的内容:

"C:\Program Files\bin\cspybat" "C:\Program Files\bin\armproc.dll" "C:\Program Files\bin\armjlink.dll" "C:\Documents and Settings\USER\Desktop\CAL\testing\Verification\FRT\Code\TC1\Output\Genericb\Debug\Exe\Gen.out" --download_only --backend -B "--endian=little" "--cpu=Cortex-M3" "--fpu=None" "-p" "C:\Program Files\CONFIG\debugger\ST\iostm32f10xxb.ddf" "--drv_verify_download" "--semihosting" "--device=STM32F10xxB" "-d" "jlink" "--drv_communication=USB0" "--jlink_speed=auto" "--jlink_initial_speed=32" "--jlink_reset_strategy=0,0" 

批处理文件运行的可执行文件名为 cspybat。可执行文件的输出提供了以下信息:--backend之后的所有参数都会传递给后端。

同时请注意,一些参数是字符串,而另一些则不是。

解决方案

现在对我有用的是:

    """ MCU flashing function""" 
params = [r"C:\Program Files\bin\cspy",
          r"C:\Program Files\bin\arpro.dll",
          r"C:\Program Files\bin\arjink.dll",
          r"C:\Documents and Settings\USER\Desktop\Exe\GenerV530b.out",
          "--download_only", "--backend", "-B", "--endian=little", "--cpu=Cort3", "--fpu=None", "-p", 
          r"C:\Program Files\CONFIG\debugger\ST\iostm32f10xxb.ddf",
           "--drv_verify_download", "--semihosting", "--device=STM32F10xxB", "-d", "jlink", "--drv_communication=USB0",
            "--jlink_speed=auto", "--jlink_initial_speed=32", "--jlink_reset_strategy=0,0" ]
print(subprocess.list2cmdline(params))
p = subprocess.Popen(subprocess.list2cmdline(params))

你能贴出你使用过的实际代码吗? - Greg Hewgill
1
@ wanderameise:请不要将澄清问题的信息发布为“答案”。这不是答案,而是必须成为问题的一部分,以便我们能够提供帮助的重要信息。请删除您的非答案,并使用附加信息更新您的问题。 - S.Lott
如果你这样调用批处理文件:cmd.exe /c batchfile.bat会发生什么?当然,你需要将batchfile.bat替换为你的文件路径。 - Geo
1
我相信你可以直接将参数传递给Popen(p = subprocess.Popen(params)),因为list2cmdline会在Popen内部调用。 - codeape
2个回答

28
在Windows中执行批处理文件的方法:
from subprocess import Popen
p = Popen("batchfile.bat", cwd=r"c:\directory\containing\batchfile")
stdout, stderr = p.communicate()

如果您不想执行批处理文件,而是直接从Python中执行您提出的命令,则需要对Popen的第一个参数进行一些实验。

首先,第一个参数可以是字符串或序列。

因此,您可以编写:

p = Popen(r'"C:\Program Files\Systems\Emb Work 5.4\common\bin\run" "C:\Program Files\Systems\Emb Work 5.4\arm\bin\mpr.dll" ... ...', cwd=r"...")

或者

p = Popen([r"C:\Program Files\Systems\Emb Work 5.4\common\bin\run", r"C:\Program Files\Systems\Emb Work 5.4\arm\bin\mpr.dll", ...], cwd=r"...")
# ... notice how you don't need to quote the elements containing spaces

根据文档:
在Windows操作系统上,Popen类使用CreateProcess()方法来执行子程序,并且操作字符串。如果args是一个序列,则会使用list2cmdline()方法将其转换为字符串。请注意,并非所有的MS Windows应用程序都以相同的方式解释命令行:list2cmdline()适用于使用与MS C运行时相同规则的应用程序。
因此,如果您使用序列,它将被转换为字符串。我建议首先尝试使用序列,这样您就不必引用包含空格的所有元素(list2cmdline()会为您完成这项工作)。
为了进行故障排除,我建议您将序列传递给subprocess.list2cmdline()并检查输出结果。
编辑后:
如果我是您,我会执行以下操作:
a) 创建一个名为testparams.py的简单Python脚本,如下所示:
import subprocess
params = [r"C:\Program Files\Systems\Emb Work 5.4\common\bin\run.exe", ...]
print subprocess.list2cmdline(params)

Great! What language pair(s) can I help you with?

关于您的第二个提议: [错误 193] %1 不是有效的 Win32 应用程序。 - binaryguy
请在您的问题中更新一个代码片段,以重现该错误。 - codeape
谢谢您的回复,但如果您能显示.bat文件应该写成绝对路径会更清晰一些……鉴于目录已经需要绝对路径,这并不是很清晰(我花了一分钟才弄明白)。 - JasonBK

0

首先,你其实并不需要所有那些引号。因此,将它们删掉吧。只有当文件名中有空格(可笑的是,Windows 经常这样)时,才需要在参数周围加上引号。

你的参数只是一串字符串列表,其中某些字符串需要加上引号。由于 Windows 使用非标准的\作为路径分隔符,所以对于这些名称,请使用“原始”字符串。

params = [
    r'"C:\Program Files\Systems\Emb Work 5.4\arm\bin\mpr.dll"',
    r'"C:\Program Files\Systems\Emb Work 5.4\arm\bin\ajl.dll"',
    r'"C:\Documents and Settings\USER\Desktop\abc.out"',
    "--backend",
    "-B", 
    "--endian=little",
    "--cpu=Cortex",
    "--fpu=None",
    "-p",
    r'"C:\Program Files\unknown\abc.ddf"',
    "--drv_verify_download",
    "--semihosting",
    "--device=STM32F10xxB",
    "-d",
    "jjftk",
    "--drv_communication=USB0",
    "--speed=auto",
    "--initial_speed=32",
    "--reset_strategy=0,0"]

使用类似于

的东西

program = r'"C:\Program Files\Systems\Emb Work 5.4\common\bin\run"'
subprocess.Popen( [program]+params )

Windows错误:[错误3]系统找不到指定的路径。 - binaryguy
哪一个?请通过更新您的问题提供详细信息。 - S.Lott
1
@S.Lott: 我认为你不应该引用包含空格的参数(在这种情况下是params[0],[1],[2]和[9])。当构建传递给CreateProcess的字符串时,subprocess.list2cmdline会根据需要引用参数。 - codeape
@codeape:我认为这取决于shell=True与shell=False的设置。shell=True需要额外的文件名引号,而shell=False则不需要。在Windows中,我通常更喜欢使用shell=True设置。 - S.Lott
@S.Lott:我在我的Windows电脑上尝试了这个。经过我的测试,看起来额外的文件名引号会导致错误,无论是使用shell=False还是shell=True。测试用例:http://pastebin.com/f3e06f80b - codeape

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