Reputation: 63
I'm on Windows using PowerShell and WSL 'Ubuntu 20.04 LTS'. I have no native Linux Distro, and I cant use virtualisation because of nested device reasons.
My purpose is to use a Windows Python script in PowerShell to call WSL to decrypt some avd-snapshots into raw-images. I already tried os.popen
, subprocess.Popen
/run
/call
, win32com.client
, multiprocessing
, etc.
I can boot the WSL shell, but no further commands are getting passed to it. Does somebody know how to get the shell into focus and prepared for more instructions?
Code Example:
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()
Upvotes: 6
Views: 6872
Reputation: 20628
There are a few ways of running WSL scripts/commands from Windows Python, but a SendKeys
-based approach is usually the last resort, IMHO, since it's:
Also, avoid the ubuntu2004.exe
(or, for other users who find this, the deprecated bash.exe
command). The much more capable wsl.exe
command is what you are looking for. It has a lot of options for running commands that the <distroname>.exe
versions lack.
With that in mind, here are a few simplified examples:
os.system
import os
os.system('wsl ~ -e sh -c "ls -l > filelist.txt"')
After running this code in Windows Python, go into your Ubuntu WSL instance and you should find filelist.txt
in your home directory.
This works because:
os.system
can be used to launch the wsl
command~
tells WSL to start in the user's home directory (more deterministic, while being able to avoid specifying each path in this case)wsl -e sh
runs the POSIX shell in WSL (you could also use bash
for this)-c "<command(s)>"
to the shell runs those commands in the WSL shellGiven that, you can pretty much run any Linux command(s) from Windows Python. For multiple commands:
Either separate them with a semicolon. E.g.:
os.system('wsl ~ -e sh -c "ls -l > filelist.txt; gzip filelist.txt')
Or better, just put them all in a script in WSL (with a shebang line), set it executable, and run the script via:
wsl -e /path/to/script.sh
That could even be a Linux Python script (assuming the correct shebang line in the script):
wsl -e /path/to/script.py
So if needed, you can even call Linux Python from Windows Python this way.
subprocess.run
The os.system
syntax is great for "fire and forget" scripts where you don't need to process the results in Python, but often you'll want to capture the output of the WSL/Linux commands for processing in Python.
For that, use subprocess.run
:
import subprocess
cp = subprocess.run(["wsl", "~", "-e", "ls", "-l"], capture_output=True)
print(cp.stdout)
As before, the -e
argument can be any type of Linux script you want.
Note that subprocess.run
also gives you the exit status of the command.
Upvotes: 9