python subprocess.call()找不到Windows Bash.exe

时间:2016-10-02 00:55:29

标签: python windows bash subprocess

我有一个程序从另一个程序获取输出,该程序在新的windows子系统上运行。我编写了一个从windows系统运行的python程序,但是将使用python子进程模块执行linux程序。如果这令人困惑,请参阅下面的示例。

然而,当我这样做时,我发现当通过python子进程调用时,windows无法找到bash程序。

Windows中命令行或powershell的示例:

C:\>bash -c "echo hello world!"
hello world!

C:\>python
Python 2.7.5 (default, May 15 2013, 22:43:36) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess as s
>>> s.call('bash -c "echo hello world"'.split())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "c:\Python27-32\lib\subprocess.py", line 524, in call
    return Popen(*popenargs, **kwargs).wait()
  File "c:\Python27-32\lib\subprocess.py", line 711, in __init__
    errread, errwrite)
  File "c:\Python27-32\lib\subprocess.py", line 948, in _execute_child
    startupinfo)
WindowsError: [Error 2] The system cannot find the file specified

>>> s.call('bash -c "echo hello world"'.split(),shell=True)
    'bash' is not recognized as an internal or external command,
    operable program or batch file.
    1

我想也许它不是以某种方式加载我的路径设置所以我输入了bash程序的完整地址。

>>> s.call(b,shell=True)
'C:\Windows\System32\bash.exe' is not recognized as an internal or external command,
operable program or batch file.
1
编辑:我意识到我的命令可能会产生问题,因为我正在拆分空间和&#34;回声问候世界&#34;是一个参数,但使用bash -c ls尝试相同的操作也会产生相同的错误

1 个答案:

答案 0 :(得分:4)

对于在WOW64子系统中运行的32位程序,&#34; System32&#34;目录gets redirected到&#34; SysWOW64&#34;。 WSL bash.exe加载程序作为64位可执行文件分发,因此从32位Python开始,您需要使用虚拟&#34; SysNative&#34;目录。例如:

import os
import platform
import subprocess

is32bit = (platform.architecture()[0] == '32bit')
system32 = os.path.join(os.environ['SystemRoot'], 
                        'SysNative' if is32bit else 'System32')
bash = os.path.join(system32, 'bash.exe')

subprocess.check_call('"%s" -c "echo \'hello world\'"' % bash)

请注意,当前Windows管道未与WSL管道桥接,因此如果您尝试使用stdout=PIPEsubprocess.check_output,则WSL bash加载程序将失败。您可以通过ReadConsoleOutputCharacter直接阅读控制台输出(例如,请参阅this answer)。或者,更简单地说,您可以将输出重定向到临时文件,将临时文件的路径转换为WSL路径。例如:

import tempfile

def wintolin(path):
    path = os.path.abspath(path)
    if path[1:2] == ':':
        drive = path[:1].lower()
        return '/mnt/' + drive + path[2:].replace('\\', '/')

cmd = '"%s" -c "echo \'hello world\' > \'%s\'"'

with tempfile.NamedTemporaryFile(mode='r', encoding='utf-8') as f:
    subprocess.check_call(cmd % (bash, wintolin(f.name)))
    out = f.read()

编辑:从Windows版本14951开始,您应该可以使用stdout=PIPE。请参阅WSL博客文章Windows and Ubuntu Interoperability