Python 的 subprocess.Popen 是不是接受路径中的空格?

Posted

技术标签:

【中文标题】Python 的 subprocess.Popen 是不是接受路径中的空格?【英文标题】: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 怎么可能处理带有空格而不转义的路径?

【问题讨论】:

相关/相同***.com/questions/804995/… cmd是字符串还是字符串列表? @beroe 类似,但不一样。就我而言,我只有一个工作方式不同的代码,有时它可以处理带有空格的路径,有时不能,我试图理解为什么。 @tdelaney 它是一个字符串 错误的回溯是什么? 【参考方案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 + '"')

【讨论】:

以上是关于Python 的 subprocess.Popen 是不是接受路径中的空格?的主要内容,如果未能解决你的问题,请参考以下文章

python中的subprocess.Popen()使用

查找 subprocess.Popen python 的执行时间

杀死使用 Python 的 subprocess.Popen() 创建的进程 [重复]

Python subprocess.Popen PIPE和SIGPIPE

python中的subprocess.Popen | 9

Python 的 subprocess.Popen 是不是接受路径中的空格?