从 Python 脚本向 WSL Shell 传递命令

Passing Commands to the WSL Shell from a Python Script

我正在 Windows 使用 PowerShell 和 WSL 'Ubuntu 20.04 LTS'。我没有原生的 Linux Distro,而且由于嵌套设备的原因我无法使用虚拟化。

我的目的是在 PowerShell 中使用 Windows Python 脚本调用 WSL 将一些 avd 快照解密为原始图像。我已经尝试了os.popensubprocess.Popen/run/callwin32com.clientmultiprocessing

我可以启动 WSL shell,但没有进一步的命令传递给它。有人知道如何让 shell 成为焦点并为更多指令做好准备吗?

代码示例:

from multiprocessing import Process
import win32com.client
import time, os, subprocess

def wsl_shell():
    shell = win32com.client.Dispatch("wscript.shell")
    shell.SendKeys("Start-Process -FilePath C:\Programme\WindowsApps\CanonicalGroupLimited.Ubuntu20.04onWindows_2004.2021.825.0_x64__79rhkp1fndgsc\ubuntu2004.exe {ENTER}")
    time.sleep(5)
    os.popen("ls -l")
    
if __name__ == '__main__':
    ps = Process(target = wsl_shell)
    ps.start()

从WindowsPython运行宁WSL scripts/commands有几种方法,但基于SendKeys的方法通常是最后的选择,恕我直言,因为它是:

  • 经常non-deterministic
  • 缺少任何控制逻辑

另外,避免ubuntu2004.exe。功能更强大的 wsl.exe 命令正是您要找的。 <distroname>.exe 版本缺少 运行ning 命令的 很多 选项。

考虑到这一点,这里有一些简化的例子:


使用os.system
import os
os.system('wsl ~ -e sh -c "ls -l > filelist.txt"')

在 运行 在 Windows Python 中输入此代码后,进入您的 Ubuntu WSL 实例,您应该会在您的主目录中找到 filelist.txt

之所以有效,是因为:

  • os.system 可用于启动 wsl 命令
  • ~ 告诉 WSL 在用户的主目录中启动(更具确定性,同时能够避免在这种情况下指定每个路径)
  • wsl -e sh 运行WSL 中的 POSIX shell(您也可以为此使用 bash
  • -c "<command(s)>" 传递给 shell 运行 WSL 中的那些命令 shell

鉴于此,您几乎可以 运行 来自 Windows Python 的任何 Linux 命令。对于多个命令:

  • 要么用分号隔开。例如:

    os.system('wsl ~ -e sh -c "ls -l > filelist.txt; gzip filelist.txt')
    
  • 或者更好,只需将它们全部放入 WSL 的脚本中(使用 shebang 行),将其设置为可执行文件,然后 运行 脚本通过:

    wsl -e /path/to/script.sh
    

    甚至可以通过 Linux Python 脚本(假设脚本中的 shebang 行正确):

    wsl -e /path/to/script.py
    

    因此,如果需要,您甚至可以通过这种方式从 Windows Python 调用 Linux Python。


使用subprocess.run

os.system 语法非常适合“即发即弃”脚本,您不需要在 Python 中处理结果,但通常您会希望捕获WSL/Linux 在 Python 中处理的命令。

为此,使用 subprocess.run:

import subprocess
cp = subprocess.run(["wsl", "~", "-e", "ls", "-l"], capture_output=True)
print(cp.stdout)

和以前一样,-e 参数可以是您想要的任何类型的 Linux 脚本。

请注意 subprocess.run 还提供了命令的退出状态。