Python Popen 在复合命令 (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 返回"系统找不到指定的路径"。路径确实存在。

如果我跑

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

它返回相同的内容。

但是,如果我运行这个:(不带分号)

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

该命令返回时没有错误。这让我相信分号是问题。这种行为的原因是什么,我该如何解决它?

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

更新:

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

powershell = C:WindowsSystem32WindowsPowerShellv1.0powershell.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!

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

虽然Windows世界 - 值得称赞 - 从CMD(cmd.exe)转向PowerShell,但Python根据COMSPEC环境变量确定要调用的shell,该变量仍然指向cmd.exe,即使在最新的W10更新中,就GUI提供的默认shell而言,它已转向PowerShell。

对于向后兼容性,这不会很快改变,而且可能永远不会改变。

因此,您的选择是:

  • 使用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,因为一旦PowerShellCore发布,该命令也有可能在Unix平台上工作。


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

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问题的主题,目的是使PowerShell的CLI与类似POSIX的shell保持一致。

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

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

最新更新