添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

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

5 人关注

我试图使用Python的Popen来改变我的工作目录并执行一个命令。

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

然而,powershell返回 "系统无法找到指定的路径"。该路径does exist.

If I run

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

它返回同样的东西。

However, if i run this: (without the semicolon)

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

该命令没有错误地返回。这使我相信是分号的问题。这种行为的原因是什么,我怎样才能绕过它?

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

UPDATE :

我测试了把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!
    
python
powershell
subprocess
popen
Jay S.
Jay S.
发布于 2017-07-14
2 个回答
mklement0
mklement0
发布于 2017-07-14
已采纳
0 人赞同

在你的 subprocess.Popen() 调用中, shell=True 表示平台的 违约 shell should be used.

虽然Windows世界正在--值得称赞--从CMD( cmd.exe )转向PowerShell。 Python根据 COMSPEC 环境变量来决定调用什么shell。 , which still points to cmd.exe 即使在最新的W10更新中,在什么方面已经向PowerShell移动。 GUI offers as the 违约 shell.

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

Therefore, your choices 是。

  • 使用 cmd 的语法,如在 莫里斯-迈耶的 答案是。

  • Do not use shell = True and invoke powershell.exe explicitly - see below.

  • Windows only :在使用 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)
    

    Note:

  • COMSPEC is only consulted on Windows;在Unix平台上,shell的可执行文件是不言而喻 /bin/sh

  • 从Windows PowerShell v5.1/PowerShell Core v6-beta.3开始,调用powershell时,只用-c(解释为-Command),仍然可以加载配置文件。by 违约,这可能会产生意想不到的副作用(在上面使用的powershell的显式调用中,-noprofile抑制了这一点)。

  • Changing the 违约 behavior to not loading the profiles is the subject of this GitHub issue, in an effort to align PowerShell's CLI with that of POSIX-like shells.
  • I'm trying to use powershell 作为默认的python操作系统外壳,但它总是加载配置文件。有没有一种解决方法可以同时做到这两点;使用python的 executable=<path-to-powershell-exe> 使用 -NoProfile 参数?作为一种选择,也许人们可以操纵环境变量 ComSpec ?但不知道这是否有帮助,因为也许这样整个环境就丢失了?
    @not2qubit ComSpec 被期望只包含一个可执行文件的路径,所以你将不能指定 -NoProfile 。不知道你说的环境丢失是什么意思。
    啊哈,好的。我的意思是,修改ComSpec可能会影响后续的调用。也就是说,如果我在Py脚本的某个地方设置了ComSpec,那么任何后续的os调用仍然会有这个功能,还是在新的 subprocess.Popen() 调用时,当指定不同的 executable 时,它被重置? 我想不会。我之所以问这些,是因为 this .
    @not2qubit 是的,任何后续的 subprocess.Popen() shell = true 的调用都会受到影响,更广泛地说,任何子进程都会看到修改后的 ComSpec 值。你可以对修改进行本地化(在调用后恢复原值),但这似乎不值得(而且它假定在修改后的值生效时没有创建子进程的代码在并行运行)。
    Maurice Meyer
    Maurice Meyer
    发布于 2017-07-14
    0 人赞同