6

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()
2
  • Welcome to Stack Overflow! You mention you are using PowerShell, but I think (if I'm reading your question correctly) it's more appropriate to say that you are using Windows Python, correct? From that Windows Python script, you want to call a WSL command-line -- Also correct? Or do you want to call a Python script in WSL? Commented Feb 23, 2022 at 20:19
  • Thanks for welcoming and responding! Im using Powershell to call my script like: python .\test.py. My final intention is to execute a command in WSL from my python script. Your comment kept me thinking about subprocess and os.popen. Always thought it get kind of pass through to the calling shell (i.e. PowerShell), but apparently not? Commented Feb 24, 2022 at 8:46

1 Answer 1

9

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:

  • Often non-deterministic
  • Lacks any control logic

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:


Using 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
  • The ~ 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)
  • Passing -c "<command(s)>" to the shell runs those commands in the WSL shell

Given 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.


Using 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.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for this answer and help. I was aware of wsl.exe, but not those flags (especially the c-flag). Microsoft documentation was not this detailed. I had problems with compiling some dependencies of the python-scripts, so i neglected 'WSL.exe' and used 'ubuntu2004.exe' instead. Im trying this!
@avatrax Most certainly! As a side note, the -c is really part of sh rather than wsl.exe, so that's why you don't see it documented on the Microsoft side. It also works for most other shells (Bash, Zsh, Fish, etc.).
It seems that you should add -d <Distro> option with wsl command, to indicate the specific distribution you want, as there could be more than one distributions installed in WSL?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.