Python Popen 在复合命令 (PowerShell) 中失败 [英] Python Popen fails in compound command (PowerShell)

查看:83
本文介绍了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 的路径作为 Popen 的 executable 参数的参数.仅仅 powershell.exe 可能还不够.要找到powershell 的真正绝对路径,请执行where.exe powershell.然后你可以将它传递给 Popen.请注意, shell 仍然是正确的.它将使用默认 shell,但将命令传递给 powershell.exe

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

解决方案

在你的 subprocess.Popen() 调用中,shell=True 意味着平台的 应该使用默认的 shell.

虽然 Windows 世界 - 值得称赞的是 - 从 CMD (cmd.exe) 转移到 PowerShell,Python 根据 COMSPEC 环境确定要调用的 shell变量,它仍然指向cmd.exe,即使在最新的 W10 更新中,在 GUI 方面已经转向 PowerShell.em> 作为默认 shell 提供.

为了向后兼容,这不会很快改变,也可能永远不会改变.

因此,您的选择是:

  • 使用 cmd 语法,如 Maurice Meyer 的回答中所建议.>

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

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

<小时>

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

导入子流程args = 'powershell', '-noprofile', '-command', 'set-location/;$密码subprocess.Popen(args)

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

<小时>

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

import os, subprocessos.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 的 CLI 保持一致.

I am trying to use Python's Popen to change my working directory and execute a command.

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

However, powershell returns "The system cannot find the path specified." The path does exist.

If I run

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

it returns the same thing.

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

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

The command returns without an error. This leads me to believe that the semicolon is issue. What is the cause for this behavior and how can I get around it?

I know I can just do c:/mydirectory/runExecutable.exe --help, but I would like to know why this is happening.

UPDATE :

I have tested passing the path to powershell as the argument for Popen's executable parameter. Just powershell.exe may not be enough. To find the true absolute path of powershell, execute where.exe powershell. Then you can pass it into Popen. Note that shell is still true. It will use the default shell but pass the command to 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!

解决方案

In your subprocess.Popen() call, shell=True means that the platform's default shell should be used.

While the Windows world is - commendably - moving from CMD (cmd.exe) to PowerShell, Python determines what shell to invoke based on the COMSPEC environment variable, which still points to cmd.exe, even in the latest W10 update that has moved toward PowerShell in terms of what the GUI offers as the default shell.

For backward compatibility, this will not change anytime soon, and will possibly never change.

Therefore, your choices are:

  • Use cmd syntax, as suggested in Maurice Meyer's answer.

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

  • Windows only: Redefine environment variable COMSPEC before using shell = True - see below.


A simple Python example of how to invoke the powershell binary directly, with command-line switches followed by a single string containing the PowerShell source code to execute:

import subprocess

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

Note that I've deliberately used powershell instead of powershell.exe, because that opens up the possibility of the command working on Unix platforms too, once PowerShell Core is released.


Windows only: An example with shell = True, after redefining environment variable COMSPEC to point to PowerShell first:

import os, subprocess    

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

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

Note:

  • COMSPEC is only consulted on Windows; on Unix platforms, the shell executable is invariably /bin/sh

  • As of Windows PowerShell v5.1 / PowerShell Core v6-beta.3, invoking powershell with just -c (interpreted as -Command) still loads the profiles files by default, which can have unexpected side effects (with the explicit invocation of powershell used above, -noprofile suppresses that).

    • Changing the default 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.

这篇关于Python Popen 在复合命令 (PowerShell) 中失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆