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

标签 python windows bash subprocess

我有一个程序可以从另一个程序中获取输出,该程序在 linux 的新 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

编辑:我意识到我的命令可能会出现问题,因为 o 在空间上 split 并且“echo hello world”是一个参数,但是用 bash -c ls 尝试同样的事情也会给出同样的错误

最佳答案

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

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 build 14951 开始,您应该能够使用 stdout=PIPE。请参阅 WSL 博客文章 Windows and Ubuntu Interoperability .

关于python subprocess.call() 找不到 Windows Bash.exe,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39812882/

相关文章:

python - 将 pandas 输出格式化为 csv

Windows 批处理 SET inside IF 不工作

Bash 如果变量是整数

python - 如何隐藏机器人框架代码库并仅将二进制文件共享给客户端?

javascript - python javascript IBMCloud 为日语重新制作 Watson-voice-bot

c# - 为什么 FileShare 不能按预期工作?

json - jq 以科学记数法重新格式化小数——这可以避免吗?

bash - &> 在 bash 中做什么?

python - 如何在Python中将多个摄像机源流传输到单个套接字

java - 检测符号链接(symbolic link)/连接点的跨平台方式?