Python Popen 在复合命令 (PowerShell) 中失败

Python Popen fails in compound command (PowerShell)

我正在尝试使用 Python 的 Popen 来更改我的工作目录并执行命令。

pg = subprocess.Popen("cd c:/mydirectory ; ./runExecutable.exe --help", stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
buff,buffErr = pg.communicate()

但是,powershell returns "The system cannot find the path specified." 路径 确实 存在。

如果我运行

 pg = subprocess.Popen("cd c:/mydirectory ;", stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)

它returns同样的事情。

但是,如果我 运行 这个:(没有分号)

pg = subprocess.Popen("cd c:/mydirectory",stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)

命令returns没有错误。这使我相信分号是问题所在。这种行为的原因是什么?我该如何解决?

我知道我可以做 c:/mydirectory/runExecutable.exe --help,但我想知道为什么会这样。

更新:

我测试过将路径传递给 powershell 作为 Popen 的 executable 参数的参数。仅 powershell.exe 可能还不够。要找到 powershell 的真正绝对路径,请执行 where.exe powershell。然后你可以将它传递给 Popen。请注意 shell 仍然成立。它将使用默认 shell 但将命令传递给 powershell.exe

powershell = C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
pg = subprocess.Popen("cd c:/mydirectory ; ./runExecutable.exe", stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, executable=powershell)
buff,buffErr = pg.communicate()
//It works!

您可以使用“&”字符而不是分号来连接多个命令。试试这个:

pg = subprocess.Popen("cd c:/mydirectory & ./runExecutable.exe --help", stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
buff,buffErr = pg.communicate()

在您的 subprocess.Popen() 调用中,shell=True 表示应使用平台的 默认值 shell。

虽然 Windows 世界正在从 CMD (cmd.exe) 转移到 PowerShell,但 Python 决定 shell 调用基于在 COMSPEC 环境变量 上, 仍然指向 cmd.exe,即使在最新的 W10 更新中,在什么方面已经转向 PowerShell GUI 默认提供 shell。

为了向后兼容,这不会很快改变,而且可能永远不会改变。

因此,您的选择是:

  • 使用 cmd 语法,如 答案中所建议。

  • 不要使用shell = True并显式调用powershell.exe - 见下文。

  • Windows:在使用 shell = True 之前重新定义环境变量 COMSPEC - 见下文。


一个简单的 Python 示例,说明如何直接调用 powershell 二进制文件,命令行开关后跟包含要执行的 PowerShell 源代码的单个字符串:

import subprocess

args = 'powershell', '-noprofile', '-command', 'set-location /; $pwd'
subprocess.Popen(args)

请注意,我特意使用 powershell 而不是 powershell.exe,因为这也开启了命令在 Unix 平台上工作的可能性,一旦 PowerShell Core 被释放。


Windows only: shell = True 的示例,在重新定义环境变量 COMSPEC 以首先指向 PowerShell 之后:

import os, subprocess    

os.environ["COMSPEC"] = 'powershell'

subprocess.Popen('Set-Location /; $pwd', shell=True)

注:

  • COMSPEC仅在Windows上查询;在 Unix 平台上,shell 可执行文件 总是 /bin/sh

  • 从 Windows PowerShell v5.1 / PowerShell Core v6-beta.3 开始,仅使用 -c 调用 powershell(解释为 -Command) 仍会默认加载配置文件 ,这可能会产生意想不到的副作用(通过上面使用的 powershell 的显式调用,-noprofile 会抑制它)。

    • 将默认行为更改为 加载配置文件是此 GitHub issue 的主题,目的是使 PowerShell 的 CLI 与 POSIX 的 CLI 保持一致-喜欢 shells.