【问题标题】:Does Python's subprocess.Popen accept spaces in paths?Python 的 subprocess.Popen 是否接受路径中的空格?
【发布时间】:2014-09-03 23:31:53
【问题描述】:

我有一个简单的 Python 脚本:

log("Running command: " + str(cmd))
process = subprocess.Popen(
    cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
    stdin=subprocess.PIPE, close_fds=close_fds)

我在 Windows 上的相同 python 版本 2.6.1 上执行它,但在不同的虚拟机上。一个是 Windows Server 2008 Enterprise,第二个是 Windows Server Enterprise,我在 only 其中一个上遇到错误。

来自 Windows Server Enterprise 的日志:

Running command: C:\Program File\MyProgram\program.exe "parameters"
Error: 'C:\\Program' is not recognized as an internal or external command

来自 Windows Server 2008 Enterprise 的日志:

Running command: C:\Program File\MyProgram\program.exe "parameters"
...

该错误仅发生在一种环境中。我知道应该对路径进行转义,但是subprocess.Popen 怎么可能处理带有空格而不转义的路径?

【问题讨论】:

  • cmd是字符串还是字符串列表?
  • @beroe 类似,但不一样。就我而言,我只有一个工作方式不同的代码,有时它可以处理带有空格的路径,有时不能,我试图理解为什么。
  • @tdelaney 它是一个字符串
  • 错误的回溯是什么?

标签: python createprocess


【解决方案1】:

带有空格的路径需要转义。最简单的方法是将命令设置为列表,添加 shell=True 并让 python 为您进行转义:

import subprocess
cmd = [r"C:\Program File\MyProgram\program.exe", "param1", "param2"]
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,stdin=subprocess.PIPE, close_fds=close_fds)

【讨论】:

  • 感谢您的回复,但这不是我问题的答案。我的问题是 - 为什么同一段代码在几乎相同的 Windows 上的相同版本的 Python 上的工作方式不同,以及 subprocess.Popen 怎么可能处理带有空格的非转义路径。它应该被转义,但事实并非如此,这段代码有效,我想知道为什么。
  • 使用shell=True 有问题(stderr 导致挂起)且不安全,因此不推荐。
  • @AlexanderTronchin-James - 越野车?如果 shell=True 导致挂起,这是我第一次听说它。 shell=True 确实存在命令注入的风险,因此不建议在任何地方使用它,但在许多情况下都可以合理使用它。例如构建系统。
【解决方案2】:

对于偶然发现这篇文章并寻找解决方案的任何人,将可执行文件封装在引号中适用于 Windows,并将 ' ' 替换为 '\ ' 在 bash (Linux/MacOS) 中适用于 Popen shell 命令。

这对我有用:

from subprocess import Popen
cmd = '/path/to/some executable with spaces'
# Execute in Windows shell:
Popen(r'"{}"'.format(cmd), shell=True)
# Execute in bash shell:
Popen(cmd.replace(' ', '\ '), shell=True)

【讨论】:

  • 您需要致电cmd.replace(' ', '\\ ')(带双反斜杠)
【解决方案3】:

考虑一下:

command = "C:\Path argument\or\path"

如何区分带有参数argument\or\path 的可执行文件C:\Path 和位于C:\Path\ argument\or 的命令path?但是,如果您将列表而不是字符串传递给 Popen,则意图是明确的:

command = ["C:\Path argument\or\path"]
proc = Popen(command, ...)

【讨论】:

  • 乔尔,感谢您的回复,但这不是问题的答案,请参阅我对@tdelaney 的评论
  • 这是一个有效的答案。如果我的命令取自变量,则上述答案中的 r"" 解决方案不起作用。
【解决方案4】:

这是我发现适用于 windows 的:

以下任一语句都将使用指定的程序打开指定的文件:

subprocess.run('start EXCEL.exe "%s"' %cmd_path, shell=True)
os.system('start EXCEL.exe "%s"' %cmd_path)

不幸的是,subprocess.run 不适用于可迭代参数。以下对我来说不起作用:

subprocess.call(['start','EXCEL.EXE', f'"%s"'%save_path])
subprocess.run(['start','EXCEL.EXE', f"%s"%save_path])
os.system('start EXCEL.EXE ' + f"%s"%save_path)

【讨论】:

    【解决方案5】:

    一个丑陋的解决方法,但是一个非常有效的解决方法 - 使用 python 使用您的命令创建批处理文件 - 执行批处理文件 - 删除批处理文件

    def runThis(command):
        tempBatch = open(r'c:\temp\TemporaryBatchFile.bat', 'w')
        tempBatch.write(command)
        tempBatch.close()
        subprocess.call(r'c:\temp\TemporaryBatchFile.bat')
    

    然后使用这样的东西:

    runThis('start "C:\\Program Files\\Microsoft Office\\root\\Office16\\WINWORD.EXE" "' + Directory + '\\' + FileName + '"')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-23
      • 1970-01-01
      • 2016-08-02
      • 1970-01-01
      • 2011-12-23
      相关资源
      最近更新 更多