jef*_*amp 2 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
Run Code Online (Sandbox Code Playgroud)
我以为也许没有以某种方式加载我的路径设置,所以我输入了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
Run Code Online (Sandbox Code Playgroud)
编辑:我意识到我的命令可能会出现问题,因为o在空格上进行了拆分,并且“ echo hello world”是一个参数,但是尝试执行相同的操作bash -c ls也会产生相同的错误
对于在WOW64子系统中运行的32位程序,“ System32”目录将重定向到“ 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)
Run Code Online (Sandbox Code Playgroud)
请注意,当前Windows管道尚未桥接到WSL管道,因此,如果您尝试使用stdout=PIPE或subprocess.check_output,则WSL bash加载器将失败。您可以通过直接读取控制台输出ReadConsoleOutputCharacter(例如,参见此答案)。或者,更简单地说,您可以将输出重定向到临时文件,并将临时文件的路径传递为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()
Run Code Online (Sandbox Code Playgroud)
编辑:从Windows内部版本14951开始,您应该可以使用stdout=PIPE。请参阅WSL博客文章Windows和Ubuntu互操作性。