How can I run a Windows executable from WSL (Ubuntu) Bash
Native solution
The official solution provided with Windows 10 Insider Preview Update (14951) is based on the almost forgotten binfmt_msc Linux facility for launching binaries. The registration command for the binfmt_misc would be like this (where /init
is the provisional binfmt_misc "interpreter" for the win-executables):
sudo echo ":WSLInterop:M::MZ::/init:" > /proc/sys/fs/binfmt_misc/register
And then win-executable would be launched like regular programs:
$ export PATH=$PATH:/mnt/c/Windows/System32
$ notepad.exe
$ ipconfig.exe | grep IPv4 | cut -d: -f2
$ ls -la | findstr.exe foo.txt
$ cmd.exe /c dir
Not that any win-executable must reside in the windows (DrvFs) file-system - not on the Linux's file-system (VolFs) - in order to inherit a proper Windows working-directory.
The cbwin alternative
Untill you get the latest build, project cbwin offers a workaround, by installing 3 new linux commands inside WSL:
wcmd
: call a win-executable throughcmd.exe
.wrun
: call a win-executable synchronously withCreateProcess
, and wait to die (not usingcmd.exe
).wstart
: launch a detached (asynchronously) command (with the use ofcmd.exe
).
In order to use them, you must:
- Install cbwin:
- a new
outbash.exe
will be installed in your regular Windows filesystem (somewhere in your%PATH%
), plus - the 3 linux-commands in the WSL filesystem.
- a new
- Use this
outbash.exe
(wherever you installed it) to start WSL, NOTC:\Windows\System32\bash.exe
! - Prefix any win-executables with one of those commands, e.g.
wrun notepad
.
Tip: If the executable launched with wcmd
or wrun
spawns any children, these survive only for as long that executable remains alive.
In other words, trying to start notepad.exe
with wcmd
won't work, because notepad will be killed just after having been launched -- Use wrun
(synchronously) or wstart
(asynchronously) in this case.
Why is Windows Subsystem for Linux able to run Windows *.exe programs?
How is WSL2 able to run Windows executables?
The Windows executable (PE binary) is added as a binfmt_misc entry in WSL2.
In simple words, binfmt_misc is a Linux kernel feature which allows
arbitrary executable file formats to be recognized and passed to certain programs.
In WSL2, the init
binary (from which every process is forked) register the
Windows PE binary as a executable and make it executable by itself (i.e. the init
).
Here is a output of the PE binfmt entry:
cat /proc/sys/fs/binfmt_misc/WSLInterop
enabled
interpreter /tools/init
flags: F
offset 0
magic 4d5a
WSLInterop
is just a name for the entry. The magic number 4d5a
is MZ
which
is first two bytes of Windows PE executable. Assume this is a fingerprint with
which init
(the interpreter) recognizes PE binary.
Users can disable the registry with this command:
echo 0 | sudo tee /proc/sys/fs/binfmt_misc/WSLInterop
Further readings:
- Windows Subsystem for Linux interoperability with Windows
- Wikipedia: binfmt_misc
- Kernel Support for miscellaneous (your favourite) Binary Formats v1.1
Run windows apps (like VSCode) in wsl
Personally i find WSL awesome (Im using WSL 1), it integrates really well with windows 10 and ubuntu. I spend most of my day in there.
I have set up alias to a few windows applications that i use a lot. Inside your ~/.bashrc or ~/.zshrc you need to add something like these to the top:
alias webstorm="/mnt/c/Program\ Files/JetBrains/WebStorm/bin/webstorm64.exe"
alias subl="/mnt/c/Program\ Files/Sublime\ Text\ 3/subl.exe"
alias chrome="/mnt/c/Program\ Files\ \(x86\)/Google/Chrome/Application/chrome.exe"
Following this pattern vs code would be something like:
alias code="/mnt/c/Program\ Files/Microsoft\ VS\ Code/Code.exe"
OR
alias code="/mnt/c/Users/damo/AppData/Local/Programs/Microsoft\ VS Code/bin/code.exe
Depending on your install location. Check your alias with alias
from within wsl.
The alternative is to ensure that your path contains the directory of the application in question. Check your path with echo $PATH
But when i installed VS code it actually put itself in the WSL path, have you tried just typing code .
does that not open vs code in your current location?
Can't launch exe file from WSL2
Did you try this ?
./testFlatScan.exe
WSL run linux from windows without spawning a cmd-window
Here's a simpler solution, which, however, requires a WSH-based helper script, runHidden.vbs
(see bottom section):
wscript .\runHidden.vbs bash -c "DISPLAY=:0 xmessage 'hello, world'"
To apply @davv's own launch-in-background technique to avoid creating a new bash
instance every time:
One-time action (e.g., at boot time): launch a hidden, stay-open bash
window. This spawns 2 bash
processes: the Windows bash.exe
process that owns the console window, and the WSL bash
process (owned by the WSL init
singleton), which is then available for servicing background commands.
wscript .\runHidden.vbs bash # hidden helper instance for servicing background commands
For every X Window-launching command: Terminate each command with &
to have it be run by the hidden WSL bash
instance asynchronously, without keeping the invoking bash
instance alive:
wscript .\runHidden.vbs bash -c "DISPLAY=:0 xmessage 'hello, world' &"
runHidden.vbs
source code:
' Simple command-line help.
select case WScript.Arguments(0)
case "-?", "/?", "-h", "--help"
WScript.echo "Usage: runHidden executable [...]" & vbNewLine & vbNewLine & "Runs the specified command hidden (without a visible window)."
WScript.Quit(0)
end select
' Separate the arguments into the executable name
' and a single string containing all arguments.
exe = WScript.Arguments(0)
sep = ""
for i = 1 to WScript.Arguments.Count -1
' Enclose arguments in "..." to preserve their original partitioning, if necessary.
if Instr(WScript.Arguments(i), " ") > 0 then
args = args & sep & """" & WScript.Arguments(i) & """"
else
args = args & sep & WScript.Arguments(i)
end if
sep = " "
next
' Execute the command with its window *hidden* (0)
WScript.CreateObject("Shell.Application").ShellExecute exe, args, "", "open", 0
Even when launched from a GUI app (such as via the Run
dialog invoked with Win+R), this will not show a console window.
If your system is configured to execute .vbs
scripts with wscript.exe
by default (wscript //h:wscript /s
, which, I think, is the default configuration), you can invoke runHidden.vbs
directly, and if you put it in your %PATH%
, by filename (root) only: runHidden ...
.
Note that use of the script is not limited to console applications: even GUI applications can be run hidden with it.
Related Topics
How to Extract Only the Raw Contents of an Elf Section
Init Function Invocation of Drivers Compiled into Kernel
How to Use Arrow Keys Alone to Expand Tree Node in Package Explorer in Eclipse on Linux
How to Check If X Server Is Running
Maximum Number of Bash Arguments != Max Num Cp Arguments
How to Make Bash Treat Undefined Variables as Errors
How to Get 'Find' to Ignore .Svn Directories
Creating Subdomains in Amazon Ec2
Splitting a File in Linux Based on Content
Differencebetween Double-Ampersand (&&) and Semicolon (;) in Linux Bash
Replacing Control Character in Sed
How to Get the Difference Between Two Dates Under Bash
Linux: Where Are Environment Variables Stored
Bash Capturing Output of Awk into Array
How to Set Process Id in Linux for a Specific Program
Why Do Shells Ignore Sigint and Sigquit in Backgrounded Processes